Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 14 Jul 2013 00:42:22 +0000 (17:42 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 14 Jul 2013 00:42:22 +0000 (17:42 -0700)
Pull networking fixes from David Miller:
 "Just a bunch of small fixes and tidy ups:

   1) Finish the "busy_poll" renames, from Eliezer Tamir.

   2) Fix RCU stalls in IFB driver, from Ding Tianhong.

   3) Linearize buffers properly in tun/macvtap zerocopy code.

   4) Don't crash on rmmod in vxlan, from Pravin B Shelar.

   5) Spinlock used before init in alx driver, from Maarten Lankhorst.

   6) A sparse warning fix in bnx2x broke TSO checksums, fix from Dmitry
      Kravkov.

   7) Dummy and ifb driver load failure paths can oops, fixes from Tan
      Xiaojun and Ding Tianhong.

   8) Correct MTU calculations in IP tunnels, from Alexander Duyck.

   9) Account all TCP retransmits in SNMP stats properly, from Yuchung
      Cheng.

  10) atl1e and via-rhine do not handle DMA mapping failures properly,
      from Neil Horman.

  11) Various equal-cost multipath route fixes in ipv6 from Hannes
      Frederic Sowa"

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (36 commits)
  ipv6: only static routes qualify for equal cost multipathing
  via-rhine: fix dma mapping errors
  atl1e: fix dma mapping warnings
  tcp: account all retransmit failures
  usb/net/r815x: fix cast to restricted __le32
  usb/net/r8152: fix integer overflow in expression
  net: access page->private by using page_private
  net: strict_strtoul is obsolete, use kstrtoul instead
  drivers/net/ieee802154: don't use devm_pinctrl_get_select_default() in probe
  drivers/net/ethernet/cadence: don't use devm_pinctrl_get_select_default() in probe
  drivers/net/can/c_can: don't use devm_pinctrl_get_select_default() in probe
  net/usb: add relative mii functions for r815x
  net/tipc: use %*phC to dump small buffers in hex form
  qlcnic: Adding Maintainers.
  gre: Fix MTU sizing check for gretap tunnels
  pkt_sched: sch_qfq: remove forward declaration of qfq_update_agg_ts
  pkt_sched: sch_qfq: improve efficiency of make_eligible
  gso: Update tunnel segmentation to support Tx checksum offload
  inet: fix spacing in assignment
  ifb: fix oops when loading the ifb failed
  ...

1207 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-devices-edac
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/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/thermal/ti_soc_thermal.txt [new file with mode: 0644]
Documentation/devicetree/bindings/timer/marvell,orion-timer.txt [new file with mode: 0644]
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/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/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/boot/dts/tegra20-seaboard.dts
arch/arm/boot/dts/tegra20-trimslice.dts
arch/arm/boot/dts/tegra20-whistler.dts
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-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/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/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-pci.c [deleted file]
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 [new file with mode: 0644]
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 [new file with mode: 0644]
arch/mips/sibyte/common/sb_tbprof.c
arch/mips/sibyte/sb1250/Makefile
arch/mips/sibyte/sb1250/bus_watcher.c [deleted file]
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/powerpc/mm/mmap.c
arch/powerpc/perf/power7-pmu.c
arch/s390/mm/mmap.c
arch/sparc/include/asm/leon.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/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/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/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/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/gpu/drm/drm_edid_load.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/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/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/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/net/ethernet/mellanox/Kconfig
drivers/net/ethernet/mellanox/Makefile
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/sun/sunvnet.c
drivers/net/phy/Kconfig
drivers/net/virtio_net.c
drivers/rapidio/switches/idt_gen2.c
drivers/remoteproc/remoteproc_core.c
drivers/remoteproc/remoteproc_debugfs.c
drivers/remoteproc/remoteproc_internal.h
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/staging/Kconfig
drivers/staging/Makefile
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/staging/ti-soc-thermal/Kconfig [deleted file]
drivers/staging/ti-soc-thermal/Makefile [deleted file]
drivers/staging/ti-soc-thermal/TODO [deleted file]
drivers/staging/ti-soc-thermal/omap4-thermal-data.c [deleted file]
drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h [deleted file]
drivers/staging/ti-soc-thermal/omap5-thermal-data.c [deleted file]
drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h [deleted file]
drivers/staging/ti-soc-thermal/ti-bandgap.c [deleted file]
drivers/staging/ti-soc-thermal/ti-bandgap.h [deleted file]
drivers/staging/ti-soc-thermal/ti-thermal-common.c [deleted file]
drivers/staging/ti-soc-thermal/ti-thermal.h [deleted file]
drivers/staging/ti-soc-thermal/ti_soc_thermal.txt [deleted file]
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 [new file with mode: 0644]
drivers/thermal/ti-soc-thermal/Makefile [new file with mode: 0644]
drivers/thermal/ti-soc-thermal/TODO [new file with mode: 0644]
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 [new file with mode: 0644]
drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h [new file with mode: 0644]
drivers/thermal/ti-soc-thermal/omap5-thermal-data.c [new file with mode: 0644]
drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h [new file with mode: 0644]
drivers/thermal/ti-soc-thermal/ti-bandgap.c [new file with mode: 0644]
drivers/thermal/ti-soc-thermal/ti-bandgap.h [new file with mode: 0644]
drivers/thermal/ti-soc-thermal/ti-thermal-common.c [new file with mode: 0644]
drivers/thermal/ti-soc-thermal/ti-thermal.h [new file with mode: 0644]
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/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/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/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/ecryptfs/crypto.c
fs/ecryptfs/file.c
fs/ecryptfs/main.c
fs/ecryptfs/messaging.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/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/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/ftrace.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/moduleparam.h
include/linux/mutex.h
include/linux/nfs_fs.h
include/linux/nmi.h
include/linux/platform_data/remoteproc-omap.h
include/linux/reservation.h
include/linux/sched.h
include/linux/socket.h
include/linux/sunrpc/cache.h
include/linux/sunrpc/gss_api.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/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/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
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/locking-selftest.c
mm/Kconfig
mm/Makefile
mm/mmap.c
mm/nommu.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_fd.c
net/9p/trans_rdma.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
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/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 481aae95c7d19c21511e3db8baf5317031fa0ccb..5c53d28f775cde36f4e77f46e41dc9ead66aa9c1 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 a0dd21c6db59ed84f06694c1ac0aa30c082800ad..6272ae5fb36699b9f47276c85ec313185e43a9cf 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 8b25ffb42562f06d473b9633b3a5ef9fea506b10..3c1cc24361bdf0ce40f13a1260fbdf98c90e7e3b 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
index 30ee78aaed75d22b3049778664f1962b98a2fc1a..6568e0010e1a9f80ff0457b7e5178340429b3158 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
index f43542ae2981c538c20fe07fdbbf17b06d259ca6..0c7195e3e0937b41c71756eee2cbfe51963cd7f9 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 bfe823dd0f31cf7c6adecb79b5b8a888f434b888..8469fe13945c524afe06a7c759d44d14e1911495 100644 (file)
@@ -140,6 +140,14 @@ structs, ioctls) must be noted in more detail in the history chapter
 (compat.xml), along with the possible impact on existing drivers and
 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>
@@ -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 e1cece6c5de1bfa44d8274f2e15afee087ca05f3..4c4603c135fe2b6843e82b542fd4e94a11cfbdfb 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>
@@ -182,21 +181,6 @@ is set, then the driver supports reading registers from the device. If
            <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. 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>
index d13bac9e244504bc6659787cd622ff883ccae680..3d038e75d12bd1fb0bba6084371b2aaa3aa72524 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>,
@@ -101,40 +101,10 @@ on the TV card.  The number zero always selects the host chip, &eg; the
 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>
@@ -198,6 +168,11 @@ to the <structfield>type</structfield> field.</entry>
            <entry><structfield>match</structfield></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>
@@ -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>
@@ -226,21 +201,6 @@ register.</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>
index fe80a183d95776da5c8841ee277496f991420c6c..222348542182bfb06b5019bbac2ea023d06bab02 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 da272c8f44e7db9e8aa41780b29bc6a95401c34b..cd556b9147868fdd4ba095a9a31f675ac0eed6d4 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 18de78599dd4861ffb5e206cfc22e11e888101c1..7f773d51fdd91acf10e49875abbe66fff0fae767 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/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 de9f6b78ee515ca3893a3ac954f2a15d516c7a76..0bf6fb7fbeabcbd4c4d14933c2b331f7fa9daa2d 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 51c776b7f7a311339432e03e1cdf52bf4df12863..96312f6c4c2651db3c0b088342b86e39af8e6cfc 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 5f8e28e2484fec501648c7055f076d288506e3f4..be45f0b1a4497bdb8c249baff41a273b0a98d80d 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/thermal/ti_soc_thermal.txt b/Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt
new file mode 100644 (file)
index 0000000..0c9222d
--- /dev/null
@@ -0,0 +1,74 @@
+* Texas Instrument OMAP SCM bandgap bindings
+
+In the System Control Module, OMAP supplies a voltage reference
+and a temperature sensor feature that are gathered in the band
+gap voltage and temperature sensor (VBGAPTS) module. The band
+gap provides current and voltage reference for its internal
+circuits and other analog IP blocks. The analog-to-digital
+converter (ADC) produces an output value that is proportional
+to the silicon temperature.
+
+Required properties:
+- compatible : Should be:
+  - "ti,omap4430-bandgap" : for OMAP4430 bandgap
+  - "ti,omap4460-bandgap" : for OMAP4460 bandgap
+  - "ti,omap4470-bandgap" : for OMAP4470 bandgap
+  - "ti,omap5430-bandgap" : for OMAP5430 bandgap
+- interrupts : this entry should indicate which interrupt line
+the talert signal is routed to;
+Specific:
+- 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.
+
+Example:
+OMAP4430:
+bandgap {
+       reg = <0x4a002260 0x4 0x4a00232C 0x4>;
+       compatible = "ti,omap4430-bandgap";
+};
+
+OMAP4460:
+bandgap {
+       reg = <0x4a002260 0x4
+               0x4a00232C 0x4
+               0x4a002378 0x18>;
+       compatible = "ti,omap4460-bandgap";
+       interrupts = <0 126 4>; /* talert */
+       gpios = <&gpio3 22 0>; /* tshut */
+};
+
+OMAP4470:
+bandgap {
+       reg = <0x4a002260 0x4
+               0x4a00232C 0x4
+               0x4a002378 0x18>;
+       compatible = "ti,omap4470-bandgap";
+       interrupts = <0 126 4>; /* talert */
+       gpios = <&gpio3 22 0>; /* tshut */
+};
+
+OMAP5430:
+bandgap {
+       reg = <0x4a0021e0 0xc
+               0x4a00232c 0xc
+               0x4a002380 0x2c
+               0x4a0023C0 0x3c>;
+       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 d209366b4a69d88b893a5428b87ba3c0555a1e69..f801d71de1cd42565e44831f25aa04c0d06ca726 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 83577f0232a0676e479bc6280ce898517a746ec8..12525b17d9ed545343bd27e952cf366c5d228f51 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 213859e69e88096fc9c45e60d6ddebd92f512e31..e349f293cc9829dc5cad185a41f95cb8627e90ea 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 75236f1972d98b3bb166b1d4706d7c4f74daa906..15356aca938cd9a7bb2cdef09d8e7a19da36db90 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 eeced24e56afc9887dbd15f92ef6e9b412206b46..f552a75c0e70b22b3800a3fa93c0783075228250 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.
 
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 bb24c2a0e870dc873ef8e8250f77d44d76a017b9..37732a220d331dcbafbf49c1fb0b04fc0cb6edad 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 bfe8c29b1f1d84cf5c6a9d71c3c69b20f2bdf12f..b937c6e2163c0997b6ffbcf4159503f1eb1bedc9 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 c55533c0adb39b5d3a243ba02a7d9a6c3c99489e..d7993dcf8537c657f0ad635410a25698d7b8d584 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 581f666a76cfc9b4200053f347b257756ee1a6c6..f14475011feab6604a8abe5edf5422cdb10a203e 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 b3ad68309109e6dae35b8fb08b82525a52e210e9..8df17d06349997f876e4ca268b7760ab9acaee1f 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 5b83a3ff15c2443a2f27d16ebbb844a2d439255e..ac8862184962ea382cda0d3ac8050f642607b92b 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 25f4d34027222d8521453f09cc1a43e62ca055c2..e51f1b5b7324baf92a620d3c941f6bae06b807ea 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 a300b283a1a093a1b68fd2240bd8efdd270f58ac..6c4866b49eb57e07b1696fc5d7fa7e4d60294b9a 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 04fddbacdbde74a03ae18ea6d91e5c0f452c0b44..f9492fed41043816eb8954ca7a56a941ea3e0235 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 44c1d934c4e3d1e0aceb48b22d9328d1bd6f8410..0da95dbaef341e08daa9033e4cf9a5d906804130 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 6a904d30d6a21e40592aec3ba33d575cc4603ff1..bf61e04291abb2f2200544517ab144c89cb3ab8e 100644 (file)
@@ -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
@@ -7004,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
@@ -7049,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
@@ -7366,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
@@ -8071,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
@@ -8079,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
@@ -8152,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/
@@ -8176,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>
@@ -8317,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
@@ -8886,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
@@ -9173,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 170ed7c159f4115ea809514921afbbace1ec8328..4e3575c7ec35e34aa0cc6ea3ddc5ae63419ed635 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -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 0ac9be677ebb34d79dd04746c54c8fd1ad36230b..ba412e02ec0c492abed190202cab324d976d0eec 100644 (file)
@@ -1316,7 +1316,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 5b7be8d975b53cbefd2b3675eb0a912f587ea97a..e401a766c0bdaf633f9dd14977eb231d2b2656e9 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 ab177b406b78053027f8fd512f71975e322c5087..365760b33a26e1ea9ac7bae3a7c32f7f4bde9878 100644 (file)
                        regulator-name = "vdd_vbus_wup1";
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
+                       enable-active-high;
                        gpio = <&gpio 24 0>; /* PD0 */
                };
        };
index 170159910455b1470928be4ccf98e39912da9d8d..ed4b901b0227405f3cd687f1a832cad4db808f22 100644 (file)
                        regulator-name = "usb1_vbus";
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
+                       enable-active-high;
                        gpio = <&gpio 170 0>; /* PV2 */
                };
        };
index ea078ab8edebdfa664cf081c456eac7b00449cae..ab67c94db280cebb2fc8c5e7126977a3fee8fb40 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 340d550c12b0aa50da1d23a75e7e2c4542c4331d..fe0bdc361d2c2fea4ebf5a274415683e07445d1a 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 a24c02443920cf03388d11c7d0d826487558f0ef..5339e6a4d639dccaca9144eb0df3101b692d0df2 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 1fdb82694ca26c0d21d3f9854fe8ef79e6833ea2..82eaa552ed14ed66cdd3359feb204f363542fd93 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 c037aa1065b7c6908d012cd0d71b9c7c3e4131df..a0025dc13021af11af524e08e8466c826f802a4a 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 18d1693736124a75205c765b5e5f588663f3b95f..0393fbab8dd5f1a572d35ccc0531af5449a398c5 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 5b391a689b47b7c75864937991d03cf5dbc9904a..76ab5ca506100c1883a8cebe57fd02eacd24a6d9 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 90525d9d290b9c25e3b40d5bdeedfc6a6f524cf6..f6fd1d4398c6febcca070a90985d3585af9a6939 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 fd38c8d22e3cd88393dc97ad85c86e4e31de9922..afbc439f11d4fba53bd3882535eda6b41540fe2f 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 99f259e8cf33133b73f2b9712746cf7ade80fcbb..5362df3df89f9b816f9db721e4188d3820d63e50 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 f5f65b58181ecd6dd860026b244dff585858cc5a..855d4a7b462d12fd0fc67b4abd3a55b0b0522530 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 686ef34c69f5d2fbf6b0faea37d07a26c7e1669d..63de1b3fd06bf0327549cf7670761ac7bccf7298 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 c9e930f29339770a79dc36bc015b28e4b45a4414..0396d89f947c879e1279f6fb3e4ca38cc02d154f 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 46a89f5e82693f930c318abb0ce61f976b324b9b..75ef03dc996490893c70c23ceea874b42747a679 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 d4cbe5e81bb4dcac1e5048fb79e10a3b1ad83d18..91242c944d7aeefc7f62cc51dd93b30486390f2e 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 c7b32a966f67e8ac7306b574204d3e07c7173913..627fa7e41fbabbeccf38c1703dc26ed2a98d66db 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 ea5a27ff994106244c0d121bfde68bbb16f37ca6..d4f671547c3756cb5d134aada03d0d2471ffa23b 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 b54562d1235e5bd0a5f89659e724e50387ae8dfb..87e65dde8e133a47baaebf7313767810c786a4d6 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 bd74f9f6063b243f523dc288d9aa3d8c1e71362f..bdd1e3a179e1cb32fe3d5aba17a09d37d2704d91 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 aef96e45cb2049c2cebba2ad50e1e8a0a8036225..3c1279f27d1fe4436595e94fb4977707a5f5fadb 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 190ae493c6efe97bf2465b93245df54106cdd02b..2ca33cc0c484055a7c4f6543b9c2a1e35adeef87 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 1c7969e965d75685ca8cd0bba8c06feba47b51ab..f3fdd6afa2137c8bb85e088d40e1e6217bf6334d 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 fe3253a100e740c92688f374557d2470ed6494cb..4a3f06f02859cbed9027288e0461691e097ba3bd 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 9ace8eae7ee8b1444aa9b0634764d2ad93871ecb..33c8846b419358693c634cca1c6b860f99c8fa6f 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 88ff83a0942eb742382ae6c1eec4e4d49951ff11..9086ce03ae12a00fa500553b80f68902c0fc852a 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 29ac667b7a8b0f194f03811d51470685979e5dca..b37e1fcbad56340a4e07a8a06e25504db2a7f457 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 461fd69a10ae58f7d7acd0672c95d9837b451d1a..f727d03f16885491dbe81dff36b74a90f6d1d874 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 899a86c31ec92213520793c4c757628a5d4b0504..1ccddd228112abbbef7d28c173155f87e4c1eb21 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 c5a75a7a508fd6f47d2acedd9ace315e599b00f5..7f45c2edbca9a457564524ee1b988cd4f9599c4b 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 4130e65a0e3f6fec890c45704ce83e47e6badc50..5b799c29886e544778d115a0e7570f3f100875ad 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 6833cbead6cc33b91863083c10e1ab8c5bd3ac4f..15225d829d7173b6169076ad063a388ceefe1248 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 10062ceadd1cc40ca48cc59e83f2deb6fc3e07da..0c6356255fe31122f2527a0a2947439e69b0e953 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 d7229d28c7f8ea9cef25d2e84db8f3a82d5b9a75..4f56617a2392d58e52f96582a3631c4c49a4f5f2 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 4143d9b0d87af3e511a5324c6528a3150f2046a2..9737e97f9f382740422f5bd431adc35933f917c0 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 49c162c03b696c9f7f9501c666d093b98a27e8ab..666e231d410b44efad2325179e205dfc07fd3560 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 7c7be78556387ed548c3c37641cef3be9441ef5a..8ed6cb1a900f2981b85dfefa00d72ac023b38177 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 4b597d91a8d5f2c44ed1f50ea0b11270d711f124..d9d81c2192534b48062fb3f4923ee8ed994dcc7a 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 beeff436b22f8128ee7d32c925321be6592242fa..4758a8fd3e99176feebe955f75ce048819d62064 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 dd58a04ef4bca5dc4a6604d283722aeb428e861c..37f9ef324f2fdea6568f93d2f4d2d12f5f2fc4a4 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 479dd4b1d0d2d21443f25fc9805ca3365c4f7f63..07eac58c3641bc9be9b8262100189c4f4b94ae50 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 5639662fd5031a005534181569e4ef628b6a5640..b78306ce56c73b5dc3cf4d083bdb3185b2ed52e7 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 9c0ddafafb6cee7116bf22638bca552c334601c4..5b974eb125fcee5f3ec2c034db14cb564a63f2f8 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
  */
@@ -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 c726a97fc7987d5cb87dfd04868ce3bf12e66cec..43da4ae04cc248f4a94f5e79ee2c07f434988ef6 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 79fe32df5e96c99da07d763e0990e07ee0321260..7e17374a9ae89fc79257b021c464c3a10d2a7f6a 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 588d1ec622e404fd2fbbe0a5d9a6868477b2c41b..172dd8397178ac4bf4259fdad99a576b9cd83029 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 3065bb61820d5befea57f31580c91c15afcc666b..d12daed749bce07c4f7e0e48bfadc5216b324144 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 d6e42c608325a85d9abb5036ad2946dbbabb11ff..3bc7f3bfc9ad5c5e45737bcf1510bfcd5b5483e7 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 c0ab3887f42ef8b355eed9971f04188be0b966d8..1525f8a3841b946889d6553ca799d2550afb8f10 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 a4b8864f93072d8e305d6a7bcca4953b2cbcc4a5..e652e578a679aa3d1c5c41e336121bedb298ad72 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 fd698087fbfd9367b777e1391aaabb53789b2936..8ac4e095e68e24b2ba3b43ba8ecc4d07e298557e 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 317931c6cf58f9305b001e25d735fcf189f18dff..acbeb1fe7c578099151195cdd5c137559a8a672c 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 24a24445db64edd7d1388c35f3bd471e049489a9..6660c7ddf87b9cf37baf6100878b52626dcf9d47 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 bbaa1d4beb6df4661b11c661ec7f066c5dc36652..bb1dbf4abb9d6516c1bea99229dd68a12d4cce2d 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 1c7b739b6a1dfcc9383e403307fbca269f3d43a6..c01d343ce6add9d6049cdcabae281c9d03d401b5 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 75a6df7fd26541c40a9052d2d54fc26b47138143..227705d9d5ae8fffacd336683d64851cca557cbe 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 3595affb97722827ddbbf5f6216511488dbe6c01..4e952043c922177590a01540af71304ae51dc120 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 1e43ccf1a792f84afa76354bf0c6f2c2c893b7b1..8a301cb12d68cf7d36b0638df1c480e8df0558ab 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 7c6497781895a040af22a8911c01afd81272b619..0a1283ce47f549d2fa8be1df16d42a83c8bc3ffd 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 389512e2abd6198d7ce16851f6ef7f0c6b36c127..7b746e7bf7a1aad7672986bb8b986b7a18716a12 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 01b1b3f94feb77b115f6911771236961ff3e151c..48b08eb9d9e4bd29dc97f5ec97c3f763852ff4aa 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
@@ -462,18 +457,6 @@ static void octeon_halt(void)
        octeon_kill_core(NULL);
 }
 
-/**
- * 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
  *
@@ -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 014ba4bbba7d25ff8c2662852955c193da8c7b0d..dace58268ce1999ca0589af0b8bd0ef291dd245a 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 9eb2f9c036aad596584427a5512255aab1769f8b..3d5d2c56de8d3a078877d349f5750040d2793270 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 d06dc5a6b8d398ec5e4f6947277af6f589d06376..cf84f01931c53e550b46ec1dec8729f8ae39c780 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 3532e2c5f098ae46a4a79f7455cd004d699dd4a9..c1516cc0285fac487631ee8ddde4afee0ffc202f 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 e5ec8fcd8afaf9d822167605a8f4aaed22e9486f..1dc086087a723fd9c90c427d05f4eb3c8ca919f6 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 dd86ab205483800c1b7b7579c22e21b970c41b4b..632bbe5a79ea5bfe53769939964ce3a4d3bfd8e9 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 17347551a1b2afd930340f0ea99b973d230594b5..a0ea69e91e2eb78f12ac1c8e4f5e2028697f965d 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 7153b32de18e6692e2792be19a34b886d1121ba8..b2e3e93dd7d88c570a6267b621cbf4521748e8c8 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 b7e59853fd33b05df930c3fb795aa03a9a6de23e..3321dd5a8872d7014fcf7d8c167e603ca0d60143 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 ac28f273449cfdde16cb2456aa24ac8af537c376..660ab64c0fc9936030c3cfc399016a1397edf26e 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 e6e65dc7d50232d979348964d71a51a7b5887b8f..19f9134bfe2fec09031945e3175006fce3ba9da4 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
@@ -193,6 +207,53 @@ enum bcm63xx_regs_set {
 #define RSET_XTMDMAS_SIZE(chans)       (16 * (chans))
 #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
  */
@@ -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
@@ -689,6 +755,52 @@ enum bcm63xx_irq {
        IRQ_XTM_DMA0,
 };
 
+/*
+ * 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
  */
index 35baa1a60a64547a7594aa30e91ee7fedcc1f101..565ff36a11195d993b4b3315e8f7536cc1830d7e 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 eff7ca7d12b09f3de2c4810fc748cbc23ccc7807..9875db31d883af0df3aa4d4b19ed6b6eb0d183e8 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 d9aee1a833f39de312e8a23571bcc9cad976000b..b86a0efba66529e3df82ffa541d20c584be1c3fe 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 94e3011ba7df99b55e5c6657e218a5cccc25e1e4..ff15e3b14e7a23e1a8768e12479b249591bdd962 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 be8fb4240cece35c234b14f43cd65a26b16a0988..47fb247f9663b501796a7c255b32525c225cffed 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 1e7dbb192657fb454c6ef91fe9db9e2fd0f4f7e9..1668ee57acb90b82e679b50b4d687940d0a9f39f 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 fe23034aaf721497af158ee2deec840038478dcf..74cb99257d5b9b25dda5aec6fa1eaa1553612086 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 7e66505fa574f3d338e0c1f50a3f5a953eaf654f..13b0751b010a71d7ac5b1c05a225220290d04f33 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 a323efb720dc01018792f76ab88f0ff093043658..b087cb83da3a51fb88af8db48e51f4feb85918b1 100644 (file)
        dsrl    \res, NSRI_NODEID_SHFT
        .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 5edf05d9dad8b648f100905c1b9b08dcdb6ca817..5d6a76434d00b12a7bb4e2078e03b86c2e8f8e49 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 bd9746fbe4af8a6b098df65c5f386cecec86f2e4..48616816bcbc9073b3184e83a6276dad687d6feb 100644 (file)
 #define ASCII_DISPLAY_WORD_BASE           0x1f000410
 #define ASCII_DISPLAY_POS_BASE    0x1f000418
 
-/*
- * Reset register.
- */
-#define SOFTRES_REG      0x1f000500
-#define GORESET                  0x42
-
 /*
  * Revision register.
  */
index 87e6207b05e4334f242cadf80b01305811edd3fd..fed1c3e9b486b7bf044f66cdedf9e2a1c302c80c 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 516e6e9a55940ec8abea80160278a744dc220c88..3b29079b5424b4fe0f78588ab1b8821aef0a1237 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 aef560a51a7e10eeceb5b8f1eda3283260e83f96..bb68c3398c8085d74170b4ef9b735a3fa0c30adb 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 a981f4681a154a53fb6fed0bffc788be83ed24a3..4b5108dfaa16ade2de259fab7c65e4cae9d05140 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 7e47209327a542b3c090560243690faebe8dda88..f4ea0f7f39657d1b30554b77c0fc6282e536c14a 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 2a78929cef7385cbe4686689de05d4f1191ad249..5604db3d18362bd4585f8d721c63466647210661 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 284fa8d773ba0774126b2387c15805110c961b82..7b7818d1e4d56686c76af4fa46552bc8fefb2ea7 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 f59552fae9173264ab58ffd3fbe95e080ec5db93..f6be4741f7e839d30d1c7d6b30ab666db4221350 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 b8e24fd4cbc5d04e3ed7a4b788e75e0943e4e128..fa8e0aa250ca08ef761117c0fe0cf1da23457cdf 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 1470b7b68b0e98996d271b25b86584fb6f3261a5..3605b844ad873b72f0881fbd48de0e8c7a3538a7 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 a89d1b10d027ce65d83eecb9dd57bfda7859400e..23fc95e65673bcb5d907a77f83714c424092add6 100644 (file)
                LONG_S  $24, PT_R24(sp)
 #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
 
                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 fd16bcb6c31111d34009b60fce8db7a1edff472a..eb0af15ac656b5757d3250ad38cd800e7ac291f1 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 895320e25662cd98a673980c449ec916841920d7..61215a34acc68ff87da07665c65c8dc0f6dbfcc1 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 680e7efebbaf6bd08246ade5a9dd14a8a6640a57..26d2ed1fa9176bc8c811673792d7f7d65a8106f7 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 0bda78f70e1e5930438c78e00897b7e86d244d75..6ca432f00860e3bf1c128e0e9d7e3f25ab1e3656 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 0f4aec2ad1e6e1c9f7d8b7a1b54cf49ebb58c392..e5a676e3d3c04ce267dc6254652ff48520565823 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 0d6c7f14de31ade52bbef1ba33506396bcf8eafb..df849e87d9aee9ffb9f6141e921e13e21f6059c8 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 87cb3085269ca49f1a3280865f43a37b6d5be74b..b26439d4ab0ba5e2a77ef337345fae830483cbc0 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 6a8714193fb9b03ad5bdeb753642e1622247961d..b7a23064841f2171173dbaca04027381000e02d4 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 97c2f81b4b43af66d766778ea2c17dcca6d8303b..ac9a8f9cd1fbfb53299e579661ce63d406cfee18 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 0845091ba480bba5313e32f7e12c2a0b79b83048..0c2e853c3db46d72d81766e5f009ad627e41bac7 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 46c2ad0703a0b1040140b4a2041c179fdaa45b34..4d78bf445a9cd2e7397898ac32e24b4ee1bac8dd 100644 (file)
@@ -467,5 +467,4 @@ unaligned:
        printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
        force_sig(SIGBUS, current);
        return -EFAULT;
-
 }
index de3c25ffd9f91e38487303696402b8c97f46bf45..0c61df281ce6788a299d655df68d874d02c6f71d 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 c6568bf4b1b05559b43bc18f65e33c84a85963ba..c7b1b3c5a761c0c46067ee940a722eb5ab490e5d 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 c61cdaed2b1d998f2614be9f9a7451837f59ebaf..09991232442394d68964efd5ac1d978afa706b5b 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
index c01b307317a9635b88394d18164710262e206234..5b5ddb231f26927bd99ba469015b1657baea903a 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 33d067148e61ba6d1526529ef735b24f2c3017c3..a03e93c4a94634b786c873f41e8b2f56846bad26 100644 (file)
@@ -168,14 +168,10 @@ 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
index 0e23343eb0a98cb2f620262e06b775c814a433de..4204d76af854209659de87b35e143ec85fb802da 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 acb34373679e21f9940f62f251e64dc1e32e5f17..8c58d8a84bf30d6a98e34f973510ebff8be006ac 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 c6a041d9d05d57fcd71f91a228c86524e00efd08..ddc76103e78c1447015ad02ccd83b2ae25c6d420 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 5712bb5322454f1a98d169e58490e77b62e149be..7e954042f2526e66f21579f73d609452a5b1d726 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 9c6299c733a317ce5c975ce91b054297502ba960..8ae1ebef8b71e67fd5e205646bd10adcdb1b0299 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 5266c6ee2b3581219dd9f4f73be1d9ddb7c1a3e8..38af83f84c4af846ce2a6fb55994804b4d781bdc 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 5e51219990aa03d5617459c818b96748b787a510..921238a6bd260d238cd2a01e177556ed105c770b 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 6fa198db89994cbe504dee1dadd51b25f9a38790..d763f11e35e2e9812a87c58e67f81759bb3dfd17 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 e9127ec612ef64cfef179cdd390412a20b43240e..e774bb1088b5f16970feaea1bddf6eaead240a01 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 97a5909a61cf0c623dfdf8284eaf11bf13e7adf7..be6627ead619e72b35bea9f8d031af3b21a2b06a 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 edcb6594e7b5b32a8d658bbe8c69de6626d4fbf0..cab150789c8d8412409506c99143a45f04717e80 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 74f485d3c0ef41bb7f73204f06a7a801d0465f13..37605dc8eef7a9c72d5743ad3ad5d1f50088fdfb 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 fd3ef2c2afbc37732d9bedcb9fff59d1dda935ea..2f285abc76d5b9be1e68920bdbe962b5c6c6d11f 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 8e393b8443f7ae4aa8c4b8a99eb1f689e49957c1..aea6c088583847d93092f4125cdfa1dca35fa495 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 a75ae40184aa3a5d35e08668e71022230ee087bc..0903d70b2cfe7940a154b8f66e8ded3762b3035b 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 203d8857070dd225f2d8fdea7bf986ad7a6560cc..c369a5d355273c49e3d7e35601afa2f86fe4fd70 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 7726f6157d9e7b0aa48c8d7e7b051c86de9aea95..cbdc4de85bb43ddd95c66a102918e9fee785bb82 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 9f9e875967aa21244e2d8578a8830096fab27c89..49c460370285900cf7abe9b788b5e346049b9753 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 f27694fb2ad191467fe523ffbca2adbe7cb25eb6..3b7f65cc42187e95627bdd14b461be0e60e7342b 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 a6eb2e853d94174f258fd063cd673d7678af6c5c..924be39e7733178309264a34b5419e460137d46a 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 f03771900813cb69c9ddd5f579841350a8c48786..e773659ccf9f8f607db709109e39b0cacb6f7989 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 e87aae1f2e802835d9a2730b5378d2bd29b8b54f..7f4f93ab22b7e207ca3899f44c11f7624672520c 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 576add33bf5bf1ae19af08a9605959b89e62f123..ee5c1ff861ae2e4d4766666ee1867c44add0eda1 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 caf92ecb37d6966639c47e6eb277d74cb42f2012..aaccf1c106997aecc8fa7050a4bfa8072212dab0 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 0fead53d1c26b261affa89d00c1fa06844f9e602..85df1cd8d446c0b7b1fccbbcb3617175f6314289 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 7e5fe2790d8a212a8d0163989280918d26a46a3c..f1baadd56e82e2b0b4f2b79bd82686ea61a112d0 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 4eb8dcfaf1ce1953760059faf151d54fe135d6a4..2c0bd580b9daafd2d650851083869a0300cc0afa 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 afeef93f81a79829ec564eaa8ddafebd4ed7e377..9ab0f907a52c60b2efc61a59e7340aa1f1543d89 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 0388fc8b5613430152a0f097c7e7d36e15aebdc6..72fdedbf76db8bd9d1d8dffc803f26fc771d8483 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 0a1339ac3ec8f8e6c3d9be6c4dc3b272d7044f98..c69da37346995e94a5e5d4a33dafce0585b84ed9 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;
        }
 
diff --git a/arch/mips/mti-malta/malta-pci.c b/arch/mips/mti-malta/malta-pci.c
deleted file mode 100644 (file)
index 37134dd..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) 1999, 2000, 2004, 2005         MIPS Technologies, Inc.
- *     All rights reserved.
- *     Authors: Carsten Langgaard <carstenl@mips.com>
- *              Maciej W. Rozycki <macro@mips.com>
- *
- * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
- *
- *  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.
- *
- * MIPS boards specific PCI support.
- */
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/gt64120.h>
-#include <asm/gcmpregs.h>
-#include <asm/mips-boards/generic.h>
-#include <asm/mips-boards/bonito64.h>
-#include <asm/mips-boards/msc01_pci.h>
-
-static struct resource bonito64_mem_resource = {
-       .name   = "Bonito PCI MEM",
-       .flags  = IORESOURCE_MEM,
-};
-
-static struct resource bonito64_io_resource = {
-       .name   = "Bonito PCI I/O",
-       .start  = 0x00000000UL,
-       .end    = 0x000fffffUL,
-       .flags  = IORESOURCE_IO,
-};
-
-static struct resource gt64120_mem_resource = {
-       .name   = "GT-64120 PCI MEM",
-       .flags  = IORESOURCE_MEM,
-};
-
-static struct resource gt64120_io_resource = {
-       .name   = "GT-64120 PCI I/O",
-       .flags  = IORESOURCE_IO,
-};
-
-static struct resource msc_mem_resource = {
-       .name   = "MSC PCI MEM",
-       .flags  = IORESOURCE_MEM,
-};
-
-static struct resource msc_io_resource = {
-       .name   = "MSC PCI I/O",
-       .flags  = IORESOURCE_IO,
-};
-
-extern struct pci_ops bonito64_pci_ops;
-extern struct pci_ops gt64xxx_pci0_ops;
-extern struct pci_ops msc_pci_ops;
-
-static struct pci_controller bonito64_controller = {
-       .pci_ops        = &bonito64_pci_ops,
-       .io_resource    = &bonito64_io_resource,
-       .mem_resource   = &bonito64_mem_resource,
-       .io_offset      = 0x00000000UL,
-};
-
-static struct pci_controller gt64120_controller = {
-       .pci_ops        = &gt64xxx_pci0_ops,
-       .io_resource    = &gt64120_io_resource,
-       .mem_resource   = &gt64120_mem_resource,
-};
-
-static struct pci_controller msc_controller = {
-       .pci_ops        = &msc_pci_ops,
-       .io_resource    = &msc_io_resource,
-       .mem_resource   = &msc_mem_resource,
-};
-
-void __init mips_pcibios_init(void)
-{
-       struct pci_controller *controller;
-       resource_size_t start, end, map, start1, end1, map1, map2, map3, mask;
-
-       switch (mips_revision_sconid) {
-       case MIPS_REVISION_SCON_GT64120:
-               /*
-                * Due to a bug in the Galileo system controller, we need
-                * to setup the PCI BAR for the Galileo internal registers.
-                * This should be done in the bios/bootprom and will be
-                * fixed in a later revision of YAMON (the MIPS boards
-                * boot prom).
-                */
-               GT_WRITE(GT_PCI0_CFGADDR_OFS,
-                        (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */
-                        (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */
-                        (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0*/
-                        ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4*/
-                        GT_PCI0_CFGADDR_CONFIGEN_BIT);
-
-               /* Perform the write */
-               GT_WRITE(GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE));
-
-               /* Set up resource ranges from the controller's registers.  */
-               start = GT_READ(GT_PCI0M0LD_OFS);
-               end = GT_READ(GT_PCI0M0HD_OFS);
-               map = GT_READ(GT_PCI0M0REMAP_OFS);
-               end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK);
-               start1 = GT_READ(GT_PCI0M1LD_OFS);
-               end1 = GT_READ(GT_PCI0M1HD_OFS);
-               map1 = GT_READ(GT_PCI0M1REMAP_OFS);
-               end1 = (end1 & GT_PCI_HD_MSK) | (start1 & ~GT_PCI_HD_MSK);
-               /* Cannot support multiple windows, use the wider.  */
-               if (end1 - start1 > end - start) {
-                       start = start1;
-                       end = end1;
-                       map = map1;
-               }
-               mask = ~(start ^ end);
-               /* We don't support remapping with a discontiguous mask.  */
-               BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
-                      mask != ~((mask & -mask) - 1));
-               gt64120_mem_resource.start = start;
-               gt64120_mem_resource.end = end;
-               gt64120_controller.mem_offset = (start & mask) - (map & mask);
-               /* Addresses are 36-bit, so do shifts in the destinations.  */
-               gt64120_mem_resource.start <<= GT_PCI_DCRM_SHF;
-               gt64120_mem_resource.end <<= GT_PCI_DCRM_SHF;
-               gt64120_mem_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1;
-               gt64120_controller.mem_offset <<= GT_PCI_DCRM_SHF;
-
-               start = GT_READ(GT_PCI0IOLD_OFS);
-               end = GT_READ(GT_PCI0IOHD_OFS);
-               map = GT_READ(GT_PCI0IOREMAP_OFS);
-               end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK);
-               mask = ~(start ^ end);
-               /* We don't support remapping with a discontiguous mask.  */
-               BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
-                      mask != ~((mask & -mask) - 1));
-               gt64120_io_resource.start = map & mask;
-               gt64120_io_resource.end = (map & mask) | ~mask;
-               gt64120_controller.io_offset = 0;
-               /* Addresses are 36-bit, so do shifts in the destinations.  */
-               gt64120_io_resource.start <<= GT_PCI_DCRM_SHF;
-               gt64120_io_resource.end <<= GT_PCI_DCRM_SHF;
-               gt64120_io_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1;
-
-               controller = &gt64120_controller;
-               break;
-
-       case MIPS_REVISION_SCON_BONITO:
-               /* Set up resource ranges from the controller's registers.  */
-               map = BONITO_PCIMAP;
-               map1 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO0) >>
-                      BONITO_PCIMAP_PCIMAP_LO0_SHIFT;
-               map2 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO1) >>
-                      BONITO_PCIMAP_PCIMAP_LO1_SHIFT;
-               map3 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO2) >>
-                      BONITO_PCIMAP_PCIMAP_LO2_SHIFT;
-               /* Combine as many adjacent windows as possible.  */
-               map = map1;
-               start = BONITO_PCILO0_BASE;
-               end = 1;
-               if (map3 == map2 + 1) {
-                       map = map2;
-                       start = BONITO_PCILO1_BASE;
-                       end++;
-               }
-               if (map2 == map1 + 1) {
-                       map = map1;
-                       start = BONITO_PCILO0_BASE;
-                       end++;
-               }
-               bonito64_mem_resource.start = start;
-               bonito64_mem_resource.end = start +
-                                           BONITO_PCIMAP_WINBASE(end) - 1;
-               bonito64_controller.mem_offset = start -
-                                                BONITO_PCIMAP_WINBASE(map);
-
-               controller = &bonito64_controller;
-               break;
-
-       case MIPS_REVISION_SCON_SOCIT:
-       case MIPS_REVISION_SCON_ROCIT:
-       case MIPS_REVISION_SCON_SOCITSC:
-       case MIPS_REVISION_SCON_SOCITSCP:
-               /* Set up resource ranges from the controller's registers.  */
-               MSC_READ(MSC01_PCI_SC2PMBASL, start);
-               MSC_READ(MSC01_PCI_SC2PMMSKL, mask);
-               MSC_READ(MSC01_PCI_SC2PMMAPL, map);
-               msc_mem_resource.start = start & mask;
-               msc_mem_resource.end = (start & mask) | ~mask;
-               msc_controller.mem_offset = (start & mask) - (map & mask);
-#ifdef CONFIG_MIPS_CMP
-               if (gcmp_niocu())
-                       gcmp_setregion(0, start, mask,
-                               GCMP_GCB_GCMPB_CMDEFTGT_IOCU1);
-#endif
-               MSC_READ(MSC01_PCI_SC2PIOBASL, start);
-               MSC_READ(MSC01_PCI_SC2PIOMSKL, mask);
-               MSC_READ(MSC01_PCI_SC2PIOMAPL, map);
-               msc_io_resource.start = map & mask;
-               msc_io_resource.end = (map & mask) | ~mask;
-               msc_controller.io_offset = 0;
-               ioport_resource.end = ~mask;
-#ifdef CONFIG_MIPS_CMP
-               if (gcmp_niocu())
-                       gcmp_setregion(1, start, mask,
-                               GCMP_GCB_GCMPB_CMDEFTGT_IOCU1);
-#endif
-               /* If ranges overlap I/O takes precedence.  */
-               start = start & mask;
-               end = start | ~mask;
-               if ((start >= msc_mem_resource.start &&
-                    start <= msc_mem_resource.end) ||
-                   (end >= msc_mem_resource.start &&
-                    end <= msc_mem_resource.end)) {
-                       /* Use the larger space.  */
-                       start = max(start, msc_mem_resource.start);
-                       end = min(end, msc_mem_resource.end);
-                       if (start - msc_mem_resource.start >=
-                           msc_mem_resource.end - end)
-                               msc_mem_resource.end = start - 1;
-                       else
-                               msc_mem_resource.start = end + 1;
-               }
-
-               controller = &msc_controller;
-               break;
-       default:
-               return;
-       }
-
-       /* Change start address to avoid conflicts with ACPI and SMB devices */
-       if (controller->io_resource->start < 0x00002000UL)
-               controller->io_resource->start = 0x00002000UL;
-
-       iomem_resource.end &= 0xfffffffffULL;                   /* 64 GB */
-       ioport_resource.end = controller->io_resource->end;
-
-       controller->io_map_base = mips_io_port_base;
-
-       register_pci_controller(controller);
-}
index 329420536241b5b70743d5ef7ce56c02a4087aa3..d627d4b2b47f4f456addef452e77c16513238bd7 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 20475c5e7b9ce383a2cf0e8ee53af773d387e7a5..e6fb24414a70e14249f8a669d6c66349bf0792be 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 e0873a31ebaace03336502d8bf57087fca3375b9..2447bf97d35ad8a30032d4773dadaba234ff6dae 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 291372a086f5a216765aaddf6560a65094463d26..362739d62b1d9ebe6d400d8b20fdc02f1aff6b76 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 9f84c60bf535a3fa034ce6fe0dcc806281d4991e..73facb2b33bbb05dcee6ed3fc782effc6028ce9c 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 ffba52489bef7b52a1dcb996cb911c277359a45d..885d293b61da1379fc550f855a64bba61236d074 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 02651748858423561ef8c4477123d44f668cc5e5..528c46c5a17028996cec33db25cb39ba258d8c9f 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 a84d6ed3746c1eb16bf4069ea0c50db306c9e2af..85ac4a892cedd0f18fb8e80970b2b81870f7538b 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 eaa99d28cb8eddbf1fe0311740f22054bb4e15ad..7b638f7be49143988b58dc8da50f9f3b186d332d 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 abb3e08cc05250498f0d9502e78ef824ec1ebd80..0cce37cbffef06816c99a0f4efcf8ae40a98d163 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 4d74f03de506800bf21716b3debdd1323f5f17e5..d428e8471eec6627b3500c4b7fd987994515d4c0 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 89c8c1066632b5f2800c1a4f2ecaef212ac890cf..214d123b79faf7f6659ae4127ffe938257fb26ae 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 3ebf7411d67b1280cc77ee857b287f32c92c6612..c06e4c9f0478ced2baea56071b14365043ea425d 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 2cb1d315d22507adefe32873747afad3e5fdaf30..c382042911ddfe138f3bdebe6b17697a80999c2a 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 2eb954239bc5bbc3b1edac6325be44f287d76235..151d9b5870bb70a4553ed3a5fc2574fd59986473 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 6eb65e44d9e4a36ef94e6967c22acb648dc7b3d0..7b2ac81e1f598fb2553edc1cd4c4659cd75882c3 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);
diff --git a/arch/mips/pci/pci-malta.c b/arch/mips/pci/pci-malta.c
new file mode 100644 (file)
index 0000000..37134dd
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 1999, 2000, 2004, 2005         MIPS Technologies, Inc.
+ *     All rights reserved.
+ *     Authors: Carsten Langgaard <carstenl@mips.com>
+ *              Maciej W. Rozycki <macro@mips.com>
+ *
+ * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
+ *
+ *  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.
+ *
+ * MIPS boards specific PCI support.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/gt64120.h>
+#include <asm/gcmpregs.h>
+#include <asm/mips-boards/generic.h>
+#include <asm/mips-boards/bonito64.h>
+#include <asm/mips-boards/msc01_pci.h>
+
+static struct resource bonito64_mem_resource = {
+       .name   = "Bonito PCI MEM",
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct resource bonito64_io_resource = {
+       .name   = "Bonito PCI I/O",
+       .start  = 0x00000000UL,
+       .end    = 0x000fffffUL,
+       .flags  = IORESOURCE_IO,
+};
+
+static struct resource gt64120_mem_resource = {
+       .name   = "GT-64120 PCI MEM",
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct resource gt64120_io_resource = {
+       .name   = "GT-64120 PCI I/O",
+       .flags  = IORESOURCE_IO,
+};
+
+static struct resource msc_mem_resource = {
+       .name   = "MSC PCI MEM",
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct resource msc_io_resource = {
+       .name   = "MSC PCI I/O",
+       .flags  = IORESOURCE_IO,
+};
+
+extern struct pci_ops bonito64_pci_ops;
+extern struct pci_ops gt64xxx_pci0_ops;
+extern struct pci_ops msc_pci_ops;
+
+static struct pci_controller bonito64_controller = {
+       .pci_ops        = &bonito64_pci_ops,
+       .io_resource    = &bonito64_io_resource,
+       .mem_resource   = &bonito64_mem_resource,
+       .io_offset      = 0x00000000UL,
+};
+
+static struct pci_controller gt64120_controller = {
+       .pci_ops        = &gt64xxx_pci0_ops,
+       .io_resource    = &gt64120_io_resource,
+       .mem_resource   = &gt64120_mem_resource,
+};
+
+static struct pci_controller msc_controller = {
+       .pci_ops        = &msc_pci_ops,
+       .io_resource    = &msc_io_resource,
+       .mem_resource   = &msc_mem_resource,
+};
+
+void __init mips_pcibios_init(void)
+{
+       struct pci_controller *controller;
+       resource_size_t start, end, map, start1, end1, map1, map2, map3, mask;
+
+       switch (mips_revision_sconid) {
+       case MIPS_REVISION_SCON_GT64120:
+               /*
+                * Due to a bug in the Galileo system controller, we need
+                * to setup the PCI BAR for the Galileo internal registers.
+                * This should be done in the bios/bootprom and will be
+                * fixed in a later revision of YAMON (the MIPS boards
+                * boot prom).
+                */
+               GT_WRITE(GT_PCI0_CFGADDR_OFS,
+                        (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */
+                        (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */
+                        (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0*/
+                        ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4*/
+                        GT_PCI0_CFGADDR_CONFIGEN_BIT);
+
+               /* Perform the write */
+               GT_WRITE(GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE));
+
+               /* Set up resource ranges from the controller's registers.  */
+               start = GT_READ(GT_PCI0M0LD_OFS);
+               end = GT_READ(GT_PCI0M0HD_OFS);
+               map = GT_READ(GT_PCI0M0REMAP_OFS);
+               end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK);
+               start1 = GT_READ(GT_PCI0M1LD_OFS);
+               end1 = GT_READ(GT_PCI0M1HD_OFS);
+               map1 = GT_READ(GT_PCI0M1REMAP_OFS);
+               end1 = (end1 & GT_PCI_HD_MSK) | (start1 & ~GT_PCI_HD_MSK);
+               /* Cannot support multiple windows, use the wider.  */
+               if (end1 - start1 > end - start) {
+                       start = start1;
+                       end = end1;
+                       map = map1;
+               }
+               mask = ~(start ^ end);
+               /* We don't support remapping with a discontiguous mask.  */
+               BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
+                      mask != ~((mask & -mask) - 1));
+               gt64120_mem_resource.start = start;
+               gt64120_mem_resource.end = end;
+               gt64120_controller.mem_offset = (start & mask) - (map & mask);
+               /* Addresses are 36-bit, so do shifts in the destinations.  */
+               gt64120_mem_resource.start <<= GT_PCI_DCRM_SHF;
+               gt64120_mem_resource.end <<= GT_PCI_DCRM_SHF;
+               gt64120_mem_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1;
+               gt64120_controller.mem_offset <<= GT_PCI_DCRM_SHF;
+
+               start = GT_READ(GT_PCI0IOLD_OFS);
+               end = GT_READ(GT_PCI0IOHD_OFS);
+               map = GT_READ(GT_PCI0IOREMAP_OFS);
+               end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK);
+               mask = ~(start ^ end);
+               /* We don't support remapping with a discontiguous mask.  */
+               BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
+                      mask != ~((mask & -mask) - 1));
+               gt64120_io_resource.start = map & mask;
+               gt64120_io_resource.end = (map & mask) | ~mask;
+               gt64120_controller.io_offset = 0;
+               /* Addresses are 36-bit, so do shifts in the destinations.  */
+               gt64120_io_resource.start <<= GT_PCI_DCRM_SHF;
+               gt64120_io_resource.end <<= GT_PCI_DCRM_SHF;
+               gt64120_io_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1;
+
+               controller = &gt64120_controller;
+               break;
+
+       case MIPS_REVISION_SCON_BONITO:
+               /* Set up resource ranges from the controller's registers.  */
+               map = BONITO_PCIMAP;
+               map1 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO0) >>
+                      BONITO_PCIMAP_PCIMAP_LO0_SHIFT;
+               map2 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO1) >>
+                      BONITO_PCIMAP_PCIMAP_LO1_SHIFT;
+               map3 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO2) >>
+                      BONITO_PCIMAP_PCIMAP_LO2_SHIFT;
+               /* Combine as many adjacent windows as possible.  */
+               map = map1;
+               start = BONITO_PCILO0_BASE;
+               end = 1;
+               if (map3 == map2 + 1) {
+                       map = map2;
+                       start = BONITO_PCILO1_BASE;
+                       end++;
+               }
+               if (map2 == map1 + 1) {
+                       map = map1;
+                       start = BONITO_PCILO0_BASE;
+                       end++;
+               }
+               bonito64_mem_resource.start = start;
+               bonito64_mem_resource.end = start +
+                                           BONITO_PCIMAP_WINBASE(end) - 1;
+               bonito64_controller.mem_offset = start -
+                                                BONITO_PCIMAP_WINBASE(map);
+
+               controller = &bonito64_controller;
+               break;
+
+       case MIPS_REVISION_SCON_SOCIT:
+       case MIPS_REVISION_SCON_ROCIT:
+       case MIPS_REVISION_SCON_SOCITSC:
+       case MIPS_REVISION_SCON_SOCITSCP:
+               /* Set up resource ranges from the controller's registers.  */
+               MSC_READ(MSC01_PCI_SC2PMBASL, start);
+               MSC_READ(MSC01_PCI_SC2PMMSKL, mask);
+               MSC_READ(MSC01_PCI_SC2PMMAPL, map);
+               msc_mem_resource.start = start & mask;
+               msc_mem_resource.end = (start & mask) | ~mask;
+               msc_controller.mem_offset = (start & mask) - (map & mask);
+#ifdef CONFIG_MIPS_CMP
+               if (gcmp_niocu())
+                       gcmp_setregion(0, start, mask,
+                               GCMP_GCB_GCMPB_CMDEFTGT_IOCU1);
+#endif
+               MSC_READ(MSC01_PCI_SC2PIOBASL, start);
+               MSC_READ(MSC01_PCI_SC2PIOMSKL, mask);
+               MSC_READ(MSC01_PCI_SC2PIOMAPL, map);
+               msc_io_resource.start = map & mask;
+               msc_io_resource.end = (map & mask) | ~mask;
+               msc_controller.io_offset = 0;
+               ioport_resource.end = ~mask;
+#ifdef CONFIG_MIPS_CMP
+               if (gcmp_niocu())
+                       gcmp_setregion(1, start, mask,
+                               GCMP_GCB_GCMPB_CMDEFTGT_IOCU1);
+#endif
+               /* If ranges overlap I/O takes precedence.  */
+               start = start & mask;
+               end = start | ~mask;
+               if ((start >= msc_mem_resource.start &&
+                    start <= msc_mem_resource.end) ||
+                   (end >= msc_mem_resource.start &&
+                    end <= msc_mem_resource.end)) {
+                       /* Use the larger space.  */
+                       start = max(start, msc_mem_resource.start);
+                       end = min(end, msc_mem_resource.end);
+                       if (start - msc_mem_resource.start >=
+                           msc_mem_resource.end - end)
+                               msc_mem_resource.end = start - 1;
+                       else
+                               msc_mem_resource.start = end + 1;
+               }
+
+               controller = &msc_controller;
+               break;
+       default:
+               return;
+       }
+
+       /* Change start address to avoid conflicts with ACPI and SMB devices */
+       if (controller->io_resource->start < 0x00002000UL)
+               controller->io_resource->start = 0x00002000UL;
+
+       iomem_resource.end &= 0xfffffffffULL;                   /* 64 GB */
+       ioport_resource.end = controller->io_resource->end;
+
+       controller->io_map_base = mips_io_port_base;
+
+       register_pci_controller(controller);
+}
index cefba7733b733100526ab450e3e34208b1e58584..9201c8b3858d9cdedfcabb388e91f5e58e0458c5 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 d38b095fd0d045a1f103eff45f9ad3f9278bb903..9f64c23878082c7e5622733486652381af0315b4 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 6b5f3406f414cd85de2230398a17ed9f7e047b3c..f25ea5b45051dc8b6a28f369f7c1a5a0623cfa7f 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 1f29e761d691e5f732f58e76708cd05c75ef0e85..da8f6816d346ea79e52d5c75d47d6264b2086265 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 2315cfeb268790a1b02fbe86575fab7b526d222b..3fbaef97a1b8d31791e8999bd222e3e1b01c3701 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 01cc1a749c73e62e0be4762ee9cd54cc8d9a3221..5fbd3605d24f50988d61731362ad1e43c720dba1 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 d03a07516f838cd8aabf2563348b9c25d0c7434e..af117330ce1423084fa179af6f1343f95b33a0e4 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 36aa700cc40c6773954306ac6ba49e8f77f0019d..b3d6bf23a6620c5837f3ac9fcc2fb3d6357cfba3 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
diff --git a/arch/mips/sibyte/common/bus_watcher.c b/arch/mips/sibyte/common/bus_watcher.c
new file mode 100644 (file)
index 0000000..5581844
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2002,2003 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; 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.
+ */
+
+/*
+ * The Bus Watcher monitors internal bus transactions and maintains
+ * counts of transactions with error status, logging details and
+ * causing one of several interrupts.  This driver provides a handler
+ * for those interrupts which aggregates the counts (to avoid
+ * saturating the 8-bit counters) and provides a presence in
+ * /proc/bus_watcher if PROC_FS is on.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/io.h>
+
+#include <asm/sibyte/sb1250.h>
+#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 {
+       uint64_t status;
+       uint32_t l2_err;
+       uint32_t memio_err;
+       int status_printed;
+       unsigned long l2_cor_d;
+       unsigned long l2_bad_d;
+       unsigned long l2_cor_t;
+       unsigned long l2_bad_t;
+       unsigned long mem_cor_d;
+       unsigned long mem_bad_d;
+       unsigned long bus_error;
+} bw_stats;
+
+
+static void print_summary(uint32_t status, uint32_t l2_err,
+                         uint32_t memio_err)
+{
+       printk("Bus watcher error counters: %08x %08x\n", l2_err, memio_err);
+       printk("\nLast recorded signature:\n");
+       printk("Request %02x from %d, answered by %d with Dcode %d\n",
+              (unsigned int)(G_SCD_BERR_TID(status) & 0x3f),
+              (int)(G_SCD_BERR_TID(status) >> 6),
+              (int)G_SCD_BERR_RID(status),
+              (int)G_SCD_BERR_DCODE(status));
+}
+
+/*
+ * check_bus_watcher is exported for use in situations where we want
+ * to see the most recent status of the bus watcher, which might have
+ * already been destructively read out of the registers.
+ *
+ * notes: this is currently used by the cache error handler
+ *       should provide locking against the interrupt handler
+ */
+void check_bus_watcher(void)
+{
+       u32 status, l2_err, memio_err;
+
+#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
+       /* Destructive read, clears register and interrupt */
+       status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
+#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");
+               status = bw_stats.status;
+               l2_err = bw_stats.l2_err;
+               memio_err = bw_stats.memio_err;
+       } else {
+               l2_err = csr_in32(IOADDR(A_BUS_L2_ERRORS));
+               memio_err = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
+       }
+       if (status & ~(1UL << 31))
+               print_summary(status, l2_err, memio_err);
+       else
+               printk("Bus watcher indicates no error\n");
+}
+
+#ifdef CONFIG_PROC_FS
+
+/* For simplicity, I want to assume a single read is required each
+   time */
+static int bw_proc_show(struct seq_file *m, void *v)
+{
+       struct bw_stats_struct *stats = m->private;
+
+       seq_puts(m, "SiByte Bus Watcher statistics\n");
+       seq_puts(m, "-----------------------------\n");
+       seq_printf(m, "L2-d-cor %8ld\nL2-d-bad %8ld\n",
+                  stats->l2_cor_d, stats->l2_bad_d);
+       seq_printf(m, "L2-t-cor %8ld\nL2-t-bad %8ld\n",
+                  stats->l2_cor_t, stats->l2_bad_t);
+       seq_printf(m, "MC-d-cor %8ld\nMC-d-bad %8ld\n",
+                  stats->mem_cor_d, stats->mem_bad_d);
+       seq_printf(m, "IO-err   %8ld\n", stats->bus_error);
+       seq_puts(m, "\nLast recorded signature:\n");
+       seq_printf(m, "Request %02x from %d, answered by %d with Dcode %d\n",
+                  (unsigned int)(G_SCD_BERR_TID(stats->status) & 0x3f),
+                  (int)(G_SCD_BERR_TID(stats->status) >> 6),
+                  (int)G_SCD_BERR_RID(stats->status),
+                  (int)G_SCD_BERR_DCODE(stats->status));
+       /* XXXKW indicate multiple errors between printings, or stats
+          collection (or both)? */
+       if (stats->status & M_SCD_BERR_MULTERRS)
+               seq_puts(m, "Multiple errors observed since last check.\n");
+       if (stats->status_printed) {
+               seq_puts(m, "(no change since last printing)\n");
+       } else {
+               stats->status_printed = 1;
+       }
+
+       return 0;
+}
+
+static int bw_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, bw_proc_show, PDE_DATA(inode));
+}
+
+static const struct file_operations bw_proc_fops = {
+       .open           = bw_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void create_proc_decoder(struct bw_stats_struct *stats)
+{
+       struct proc_dir_entry *ent;
+
+       ent = proc_create_data("bus_watcher", S_IWUSR | S_IRUGO, NULL,
+                              &bw_proc_fops, stats);
+       if (!ent) {
+               printk(KERN_INFO "Unable to initialize bus_watcher /proc entry\n");
+               return;
+       }
+}
+
+#endif /* CONFIG_PROC_FS */
+
+/*
+ * sibyte_bw_int - handle bus watcher interrupts and accumulate counts
+ *
+ * notes: possible re-entry due to multiple sources
+ *       should check/indicate saturation
+ */
+static irqreturn_t sibyte_bw_int(int irq, void *data)
+{
+       struct bw_stats_struct *stats = data;
+       unsigned long cntr;
+#ifdef CONFIG_SIBYTE_BW_TRACE
+       int i;
+#endif
+
+#ifdef CONFIG_SIBYTE_BW_TRACE
+       csr_out32(M_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
+       csr_out32(M_SCD_TRACE_CFG_START_READ, IOADDR(A_SCD_TRACE_CFG));
+
+       for (i=0; i<256*6; i++)
+               printk("%016llx\n",
+                      (long long)__raw_readq(IOADDR(A_SCD_TRACE_READ)));
+
+       csr_out32(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
+       csr_out32(M_SCD_TRACE_CFG_START, IOADDR(A_SCD_TRACE_CFG));
+#endif
+
+       /* Destructive read, clears register and interrupt */
+       stats->status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
+       stats->status_printed = 0;
+
+       stats->l2_err = cntr = csr_in32(IOADDR(A_BUS_L2_ERRORS));
+       stats->l2_cor_d += G_SCD_L2ECC_CORR_D(cntr);
+       stats->l2_bad_d += G_SCD_L2ECC_BAD_D(cntr);
+       stats->l2_cor_t += G_SCD_L2ECC_CORR_T(cntr);
+       stats->l2_bad_t += G_SCD_L2ECC_BAD_T(cntr);
+       csr_out32(0, IOADDR(A_BUS_L2_ERRORS));
+
+       stats->memio_err = cntr = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
+       stats->mem_cor_d += G_SCD_MEM_ECC_CORR(cntr);
+       stats->mem_bad_d += G_SCD_MEM_ECC_BAD(cntr);
+       stats->bus_error += G_SCD_MEM_BUSERR(cntr);
+       csr_out32(0, IOADDR(A_BUS_MEM_IO_ERRORS));
+
+       return IRQ_HANDLED;
+}
+
+int __init sibyte_bus_watcher(void)
+{
+       memset(&bw_stats, 0, sizeof(struct bw_stats_struct));
+       bw_stats.status_printed = 1;
+
+       if (request_irq(K_INT_BAD_ECC, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
+               printk("Failed to register bus watcher BAD_ECC irq\n");
+               return -1;
+       }
+       if (request_irq(K_INT_COR_ECC, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
+               free_irq(K_INT_BAD_ECC, &bw_stats);
+               printk("Failed to register bus watcher COR_ECC irq\n");
+               return -1;
+       }
+       if (request_irq(K_INT_IO_BUS, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
+               free_irq(K_INT_BAD_ECC, &bw_stats);
+               free_irq(K_INT_COR_ECC, &bw_stats);
+               printk("Failed to register bus watcher IO_BUS irq\n");
+               return -1;
+       }
+
+#ifdef CONFIG_PROC_FS
+       create_proc_decoder(&bw_stats);
+#endif
+
+#ifdef CONFIG_SIBYTE_BW_TRACE
+       csr_out32((M_SCD_TRSEQ_ASAMPLE | M_SCD_TRSEQ_DSAMPLE |
+                  K_SCD_TRSEQ_TRIGGER_ALL),
+                 IOADDR(A_SCD_TRACE_SEQUENCE_0));
+       csr_out32(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
+       csr_out32(M_SCD_TRACE_CFG_START, IOADDR(A_SCD_TRACE_CFG));
+#endif
+
+       return 0;
+}
+
+__initcall(sibyte_bus_watcher);
index 2188b39a1251a9191409150a65b5650cda527655..059e28c8fd973f8e9e40ab23973e9a3fb71563cb 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 d3d969de407ba6be81175085a1577f566c94b088..cdc4c56c3e29238158cafa0e09422780e46af1ac 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
diff --git a/arch/mips/sibyte/sb1250/bus_watcher.c b/arch/mips/sibyte/sb1250/bus_watcher.c
deleted file mode 100644 (file)
index 8871e33..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2002,2003 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; 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.
- */
-
-/*
- * The Bus Watcher monitors internal bus transactions and maintains
- * counts of transactions with error status, logging details and
- * causing one of several interrupts.  This driver provides a handler
- * for those interrupts which aggregates the counts (to avoid
- * saturating the 8-bit counters) and provides a presence in
- * /proc/bus_watcher if PROC_FS is on.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <asm/io.h>
-
-#include <asm/sibyte/sb1250.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_int.h>
-#include <asm/sibyte/sb1250_scd.h>
-
-
-struct bw_stats_struct {
-       uint64_t status;
-       uint32_t l2_err;
-       uint32_t memio_err;
-       int status_printed;
-       unsigned long l2_cor_d;
-       unsigned long l2_bad_d;
-       unsigned long l2_cor_t;
-       unsigned long l2_bad_t;
-       unsigned long mem_cor_d;
-       unsigned long mem_bad_d;
-       unsigned long bus_error;
-} bw_stats;
-
-
-static void print_summary(uint32_t status, uint32_t l2_err,
-                         uint32_t memio_err)
-{
-       printk("Bus watcher error counters: %08x %08x\n", l2_err, memio_err);
-       printk("\nLast recorded signature:\n");
-       printk("Request %02x from %d, answered by %d with Dcode %d\n",
-              (unsigned int)(G_SCD_BERR_TID(status) & 0x3f),
-              (int)(G_SCD_BERR_TID(status) >> 6),
-              (int)G_SCD_BERR_RID(status),
-              (int)G_SCD_BERR_DCODE(status));
-}
-
-/*
- * check_bus_watcher is exported for use in situations where we want
- * to see the most recent status of the bus watcher, which might have
- * already been destructively read out of the registers.
- *
- * notes: this is currently used by the cache error handler
- *       should provide locking against the interrupt handler
- */
-void check_bus_watcher(void)
-{
-       u32 status, l2_err, memio_err;
-
-#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
-       /* Destructive read, clears register and interrupt */
-       status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
-#else
-       /* Use non-destructive register */
-       status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS_DEBUG));
-#endif
-       if (!(status & 0x7fffffff)) {
-               printk("Using last values reaped by bus watcher driver\n");
-               status = bw_stats.status;
-               l2_err = bw_stats.l2_err;
-               memio_err = bw_stats.memio_err;
-       } else {
-               l2_err = csr_in32(IOADDR(A_BUS_L2_ERRORS));
-               memio_err = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
-       }
-       if (status & ~(1UL << 31))
-               print_summary(status, l2_err, memio_err);
-       else
-               printk("Bus watcher indicates no error\n");
-}
-
-#ifdef CONFIG_PROC_FS
-
-/* For simplicity, I want to assume a single read is required each
-   time */
-static int bw_proc_show(struct seq_file *m, void *v)
-{
-       struct bw_stats_struct *stats = m->private;
-
-       seq_puts(m, "SiByte Bus Watcher statistics\n");
-       seq_puts(m, "-----------------------------\n");
-       seq_printf(m, "L2-d-cor %8ld\nL2-d-bad %8ld\n",
-                  stats->l2_cor_d, stats->l2_bad_d);
-       seq_printf(m, "L2-t-cor %8ld\nL2-t-bad %8ld\n",
-                  stats->l2_cor_t, stats->l2_bad_t);
-       seq_printf(m, "MC-d-cor %8ld\nMC-d-bad %8ld\n",
-                  stats->mem_cor_d, stats->mem_bad_d);
-       seq_printf(m, "IO-err   %8ld\n", stats->bus_error);
-       seq_puts(m, "\nLast recorded signature:\n");
-       seq_printf(m, "Request %02x from %d, answered by %d with Dcode %d\n",
-                  (unsigned int)(G_SCD_BERR_TID(stats->status) & 0x3f),
-                  (int)(G_SCD_BERR_TID(stats->status) >> 6),
-                  (int)G_SCD_BERR_RID(stats->status),
-                  (int)G_SCD_BERR_DCODE(stats->status));
-       /* XXXKW indicate multiple errors between printings, or stats
-          collection (or both)? */
-       if (stats->status & M_SCD_BERR_MULTERRS)
-               seq_puts(m, "Multiple errors observed since last check.\n");
-       if (stats->status_printed) {
-               seq_puts(m, "(no change since last printing)\n");
-       } else {
-               stats->status_printed = 1;
-       }
-
-       return 0;
-}
-
-static int bw_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, bw_proc_show, PDE_DATA(inode));
-}
-
-static const struct file_operations bw_proc_fops = {
-       .open           = bw_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static void create_proc_decoder(struct bw_stats_struct *stats)
-{
-       struct proc_dir_entry *ent;
-
-       ent = proc_create_data("bus_watcher", S_IWUSR | S_IRUGO, NULL,
-                              &bw_proc_fops, stats);
-       if (!ent) {
-               printk(KERN_INFO "Unable to initialize bus_watcher /proc entry\n");
-               return;
-       }
-}
-
-#endif /* CONFIG_PROC_FS */
-
-/*
- * sibyte_bw_int - handle bus watcher interrupts and accumulate counts
- *
- * notes: possible re-entry due to multiple sources
- *       should check/indicate saturation
- */
-static irqreturn_t sibyte_bw_int(int irq, void *data)
-{
-       struct bw_stats_struct *stats = data;
-       unsigned long cntr;
-#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));
-       csr_out32(M_SCD_TRACE_CFG_START_READ, IOADDR(A_SCD_TRACE_CFG));
-
-       for (i=0; i<256*6; i++)
-               printk("%016llx\n",
-                      (long long)__raw_readq(IOADDR(A_SCD_TRACE_READ)));
-
-       csr_out32(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
-       csr_out32(M_SCD_TRACE_CFG_START, IOADDR(A_SCD_TRACE_CFG));
-#endif
-
-       /* Destructive read, clears register and interrupt */
-       stats->status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
-       stats->status_printed = 0;
-
-       stats->l2_err = cntr = csr_in32(IOADDR(A_BUS_L2_ERRORS));
-       stats->l2_cor_d += G_SCD_L2ECC_CORR_D(cntr);
-       stats->l2_bad_d += G_SCD_L2ECC_BAD_D(cntr);
-       stats->l2_cor_t += G_SCD_L2ECC_CORR_T(cntr);
-       stats->l2_bad_t += G_SCD_L2ECC_BAD_T(cntr);
-       csr_out32(0, IOADDR(A_BUS_L2_ERRORS));
-
-       stats->memio_err = cntr = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
-       stats->mem_cor_d += G_SCD_MEM_ECC_CORR(cntr);
-       stats->mem_bad_d += G_SCD_MEM_ECC_BAD(cntr);
-       stats->bus_error += G_SCD_MEM_BUSERR(cntr);
-       csr_out32(0, IOADDR(A_BUS_MEM_IO_ERRORS));
-
-       return IRQ_HANDLED;
-}
-
-int __init sibyte_bus_watcher(void)
-{
-       memset(&bw_stats, 0, sizeof(struct bw_stats_struct));
-       bw_stats.status_printed = 1;
-
-       if (request_irq(K_INT_BAD_ECC, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
-               printk("Failed to register bus watcher BAD_ECC irq\n");
-               return -1;
-       }
-       if (request_irq(K_INT_COR_ECC, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
-               free_irq(K_INT_BAD_ECC, &bw_stats);
-               printk("Failed to register bus watcher COR_ECC irq\n");
-               return -1;
-       }
-       if (request_irq(K_INT_IO_BUS, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
-               free_irq(K_INT_BAD_ECC, &bw_stats);
-               free_irq(K_INT_COR_ECC, &bw_stats);
-               printk("Failed to register bus watcher IO_BUS irq\n");
-               return -1;
-       }
-
-#ifdef CONFIG_PROC_FS
-       create_proc_decoder(&bw_stats);
-#endif
-
-#ifdef CONFIG_SIBYTE_BW_TRACE
-       csr_out32((M_SCD_TRSEQ_ASAMPLE | M_SCD_TRSEQ_DSAMPLE |
-                  K_SCD_TRSEQ_TRIGGER_ALL),
-                 IOADDR(A_SCD_TRACE_SEQUENCE_0));
-       csr_out32(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
-       csr_out32(M_SCD_TRACE_CFG_START, IOADDR(A_SCD_TRACE_CFG));
-#endif
-
-       return 0;
-}
-
-__initcall(sibyte_bus_watcher);
index cec4b8ca143817c7c74c422dfa644166359bf420..12336c2a649c4c3eb9bc117e7fafddf4b3ad77b9 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 7cddd03d1fea794b5bbdd236761ccdc2e5b6b510..05bb51676e82e5649d3d37b0c1f0ab4735417219 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 67a42ed0d2fc8408c7ecb197a3c5bf58c5bee6df..cb8bdbe4972fa8bbe4c63039537ab9cbd4ccb233 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 13c3f0e547a201947029c7f0096b2caeba03f30a..d1821b8bbc4c778024b9fbe424a0740671ca3c9d 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 06bafec00278c654d616c731a2711a0b7b5beced..40023290ee5b43dea2cf72b68c97f9495b6c59fd 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 b836e9297f2a71c3084df4cd695109474856d72d..c2f6ff6d7a35aa041507a25d75b4dcc5c1c8ce20 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 961b87f99e694959a9575d5b8aaef0cc37de026b..f76389a3234229a4a99e61ae55a8c70476b5798b 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 5ef48dab563694db95935564e5df92172fd67bab..11d460f6f9cc70ddbf37b75bed4803b782672dad 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 2daaaa6eda234df1ed86702f58a1d6f607b35ff4..51561b8b15baf916f7d5cb5e5cc0db3d8eb6032f 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 44aad32eeb4e604ff1f17730f218285f80659807..969f96450f690a8bc06c159bfc0045479f55a006 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 c801c3953a00abec66285477c823d944a14040f3..5d2b88d394243157f895c35c330ac51305868e79 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 4e55e8f76648a27da7ff666b0fae21590e182651..bf10a345fa8b7857a9e080ef4baa44998ea36d55 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 bf8ee0613ae7efdb1bb6d6897bb42a11b7621b4b..852257fcc82b83c508bb738b31490d8694cef2dc 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 f96f4cec602ad6bd3f15e2502f6b35ae369bd05f..d67d91ebf63e693e1562f2b465de5e69fe490547 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 52ff81cce008e6dbaed3d3a3b290ea6c88412897..bae3aba95b15ab298562afe1b657d63b706578e0 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 6b52980c29c10be9673c2aed2acc68176377d547..29e3093bbd2132d89e8b22d0150a3088d6e4b1da 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 98f2083832ebec3c5b6fe65300603fa1777b3180..41e8e00a663703df0592eec7be74aea5c181979c 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 0db655ef39188917c4d114cf509ba783513cff2e..639d1289b1ba9a16cc7b9684d3697f5b79df0d27 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 0920212e6159a27b552925e7f26d5efa584d0440..ba77ebc2c35321dc4085c06a106f715ec18d9a21 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 a7e18551c9689b5192d528ccae10ee9dbb20e84a..064d0be67ecc23734aa465541138d9b5be295277 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 845df6835f9ff5fc216ab01857100d41eba77fbf..62c29a5bfe26aeb67bf63fb545294b79765e445f 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 0a1b95f81a32b165ae27421fbddf2423a4da4ca9..7ea6451a3a33207508660141670cafeb309c309e 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 a34010e0e51c3fcfece542266886ced6563a47eb..af7da74d535f1870c8c266c2caf6d6fa1f2b79c5 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 ad8952e8a07f6d369192416d831917cd642f9075..6868f2ca6af83372bfd336686e07a14d9c231b66 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 0c25799facabf9ab9fb50d73e6707b6846a12994..23392c5630ce9939b04bae3ff6de4fd67417852a 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 d9ab131bc1aa8c8cefa243f97bb6e9d5e8561161..370b26f38414d9e33af67244a96bc7c9a8a96622 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 61fc5faeb46c65e8be7a613328daf4204bbf2781..3899610c1dfff71a53e0144969fd990e59e75f62 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 36dc7a6843978253a0373eda900e9afedfbb4922..73cc3f482304e35f9144d451e3fefab59fe8c6c0 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 8f017eb309bda442652463f0fb4d8f1732c145d6..0fdf5d043f82ab16a3f1b50766101392cadd483f 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 ec098b68fb9a8035e2907c557a342622bb7488d4..32e98f27ce9797cc6b82427ce9e98a3083158794 100644 (file)
@@ -29,11 +29,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.
  */
index 3d35e5d0367e01dbb04ae2ae075f6ceab5e24058..69f901713fb6fd754301d35372eaf2f54a543c7f 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
 
 
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 1e7fc87a94bb80b5894f8ce0cc471090ab883241..f90265ec1ccca1bd5fed0849ffb708d6f7d965e8 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 5082507d5631b3e6bf865ab82d40bb1975bffc3a..9298742f0fd0a01f9df2af3af0c689d9248c9545 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 ef12c0e6fa257e907ce7202b4202fce05adbf6ad..7d740ebbe198ec77a8011601f4172ebc809b9be8 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 126c18839409cbc1d19af546f6884f431f2b5f83..5b3403388d7f0b0465d3f1d00bdd2abb36c9410d 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 2bd6c351f37c6dac1417c16380847f15d9110588..1cf008284dd2925599df108f776ccdfb2e10e222 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 6dd25ecde3f5ce57b036ab59458497edd7971156..42a8bba0b0ead4235add5133b7e849187641da53 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 ffb4741043116dc0bb76a5ccdb11f161257ac9cd..bdbb173125269afdf9a0bff5981a27e995fa05dc 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 42c53c87c204171bea361b91913d7fba579ce9b7..d8507f812f46ef6cb05425381ac54e323d028126 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 5411aa67c68e6970b8dedc22d448a2c0edd096ff..ca9d2366bf12b5b85dad9c4fd1295ed14a02d2a5 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 7d0fea6d7f20456feae6c5f353a60e7d53966daa..56f88b7afe2fd907798cd41023133e11c37cf7c8 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 c0edb35424cea9ed8a077b25d682202f9d50e533..8c6e819cd8edcc26049348a9ca2e4a6d59c677b3 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 96ef8eeb064e745694d6ec7912904838364e31fe..74bb74fa3f878e374dafc18fe5934945b08e4c6f 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 54b2b573f166947538a6bc590504821e539928d7..39154563ee176f2b75506c0b06241e2f7ad3e578 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 e8918ffaf96d4a0a2dacf75838b5d8a89e5e8ca3..290792a13e3cc184f0ea67176589050e6323b675 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 4e595ee8c9151aea5c0005bffbe1d936c4603083..8056c03a3382f595212530f6bd1c4dd1a5282ac8 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 cc345e1d8d4ea0088832833ef985d6b1e764fa44..3f33d86722688a4f50ac0064488540d1960447fb 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 31146225f3d078fb5326e30195a0fa138f1f3e5a..08a32dfd3844cfeeacae4d38164c96f05f1b0c83 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 d5cd3131c57a36645bcf049e28ab9a46ab5ea559..d5bbdcfd0dab5f56fa76f9ca08dc979fe16d1a35 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 ba19a3afab7929cf3ff0857683ccaef40a007a77..20614a33236220d0e79d99a2cfaf99822327bc57 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 eba5b04c29b135bdc6b84ac80690d380d59dd8a5..668394d185885bc3fcc878697878a4cb07be899e 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 5d1bf70e33d5a04a5fc994c8a8cb0c9ecdbf0900..3de89d4690f3bf3e0d9abec1976a379b5dc171e5 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 e9e8bb24785b45e267b810fe8a7582ab22468d35..4ab807dc851812a8c4d64265298f38c610bf22ba 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 14de9f46972ee798926e9a1805c356fc02bb291e..826560753389ca3f1d2dd1bc2670f15f059970ae 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 8d1c0105e1138141aa2b6c988657d261617546ee..5b02a0aa540cfa122ecfd8481d38162076cefbde 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 288bb270f8edc11cb0d92e23f7b759619e35e660..5c28c894c0fc204925f489fdf988a01abb74bc88 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 dfe76f17cfc4740e0f260c70b25023339d37c210..10985573aaa7c680613c1412c958d81d7af22f64 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 aba6e93b0502e0b966366e4565934fb80f3da9c0..80dc988f01e4f1eebb7d12311ab98c8ac48dc013 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 08fe897c0b4cfcdc4c2eed939870cf46ddf57735..6687ba7418796429c95077de55c0664035b4d7ea 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 2f9dbf7568fb5fd2d4e42420e6d98068aea88e6a..40a865449f35bf80a7b035ed02a6904c3767b674 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 81465c21f873ec37ec07213b62d81559a24335bf..b7b9b040a89ba807e36062c2029feedfceee8016 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 9ba8b4d867e3254528d913163b74f59744568449..8b00c5cebfa43d5295ccbb11d8ed95240ee2a9c0 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 6a015ada5285720389d1191a210d541f41b429fe..0937b8d6c2a4cebe904bbc9c5cdbf24afd2a681f 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 a697a64d53837bda97602e2948fb165f73a57312..878f09005fad99a57e7f04e648d9828f87c0dc5c 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 a4f5ce14dc1cdca1970a689ab19f6c10144aec8d..271b42bbfb72152dc3d1e66662a981cee4a5fb6e 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 fdc2ab4af315f75fd7b23360af9c60783a18214f..dc6dea614abd68dca0e32f7d6948b9c8e40696ef 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 7e27d3295e55e06bbdbbb15ea922756bbe48b775..300daabaa5753a46fa8226d3ce313865d225a753 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 51beb85250d4400a06e90eca0b4f539825cc7438..0a8440ae05656569a9694f7bdb9f8406118ac785 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 729428edeba26c4fca4ddfde7c9615f76a0c76b5..dabb88b1cbec69052d32eb5e84b7f647534a4599 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 91d49dd957ef634f02a6c9657afe236524d3a936..ede8575ac7d5d12e9d8fe1c20d3d2a9ab2cde013 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 c0ab800b7bb34f228cc6488a966cfad588c1f765..4ecdee5eca83d283feba4e25f70609745f25d00c 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 c85b56c28099c6c60b2341b09060df348fbe6262..5ceda710f516bc4721e14961a504fa7e2c3054a9 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 b126fefe0b1c7bdd1941ab27dcca4e0b34d05ec5..1fe69888515f32cdd5f20f20b9a1d9d5f79876b6 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 eaec8d7a3b7372094cdabcb98c2277fd46bb93cf..e90f2b2eabd724cddc3d8ade1566c2dd849b5bcd 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 34fbc2f60a09debc72652b4e8ab8dcef0d09dbe7..f1c279fabe646f80d3962f3354475087f9c37bf8 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 934f45e79e5e3f05b47e5327aeac1c0f26e6648f..9838ca484389c654f915d4ba79acf1fb37e9bafc 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 99904f7d59e3ccda6cbffeaa6c0c2d2b66924690..cde1e7b5b85ddd87b1e44e9886be0be19bf3d137 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 5ca44cd9b00cc5113968077783400c59912503b9..b0f189be543bf61749bdcf37d6fd7a17f3d57fcc 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 a7d00f6b3bc1c8b2c2ac5cfab340adebd375e7cb..b3c07b0c9f2655bb13b9fb81c6ef38fc2efd8757 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 e5649e8b215d90f038c9cc3f2d61bf0a796bcf43..b57c0befd962b837f45b36719663a945caf3cdbe 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 982e3efd98d3ef6d1f6c3cbce6b894e494c0f870..cd8d290a09fc2029f5542660c42e652b9216fe3e 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 48970af236794cea69ace19502a874071c1ee0cb..d540180a8e420865a71387a630a509b203959747 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 71942af4fce94695753dacbb8417ee191aaaf9a6..0965278dd2ed7e805f7c1a8e1d9eae03b9c3765b 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 48928c8e7774203479bd0407ae0e41b48acfc720..ded416f1adea559d1f1db591a6641237e551b195 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 c75cbdfa87e7b82a3e3d6cd5d1e7be78b4dd1f19..36b062da2aea4218d14b77ded42fbc9f05fea383 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 b29a4246ef41ef6068372398ed23134cceae3384..dcfbab177faa63eee063a428ac7848e5763f8125 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 1e603a375069022bfed295f071f8c729b4ad826b..d03ca4c1ff250d8345d5ebbda2c84d49a38a4ff4 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 f12d7bb8b39f53b29ff3acf753f8eca0dae6145c..57f8103e51f83089d4068889e8ade5a409a95e46 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 4d11575c2010aad700ef81acd4e2ff4581d091a6..4a9af795b88f3bf5ba2fc8a8d44aaf637a318029 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 d39e0183ff822ceb71fe19b3e212ef5aa1125dca..4f255b723ffd786b3378a4e7920937af9cbb72f8 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 5246aa486bbefa6f24769a5c3081d723d641736a..ab4e11cfab15e3f5f4cb0fbfce159747e150ddda 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 216092477dfcf7eb4a51187ffe825110c5eb3286..5bee08f16d7438d2eba1668bdccee64265c9972d 100644 (file)
@@ -558,7 +558,6 @@ move_along:
        }
 
        rcd->head = l;
-       rcd->pkt_count += i;
 
        /*
         * Iterate over all QPs waiting to respond.
index 9dd0bc89c3aa83a6bf4b89faa3ce6c20e4648e3e..b51a51486cb845479b0512dc2b9f31c1443f9649 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 0232ae56b1fa2b185e1a551e074e5d256f15c087..84e593d6007b5c31a3ef0cc080c243697de10027 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 64d0ecb90cdc43b2136b6ed646a49c2c199abee4..454c2e7668fe71815f80cdabed08bacb35863ec0 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 3f6b21e9dc110513c0522b099adcfa0f131ef6b4..21e8b09d4bf87687a9c569ac87dae42108b7cd8a 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 173f805790da4522f3f4a8881b8b2df5883b9b4b..36e048e0e1d93bca227707a2c5e569ec4a851a78 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 a6a2cc2ba260ddd80ca6e23982864ec8e969e9b4..3cca55b51e54cd93aab8d11c11096ed77f792d47 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 3fc51443121252e38aa02d2e4ced4dde868be17e..32162d355370f95b56970b19da33783052c24c36 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 904c384aa36142b95455066cd6fcf80510b80959..092b0bb1bb789aaa78cc74add2fcb0aae24bb94e 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 aff8b2c178869ce31503b7981ed5d7c8df456469..012e2c7575ad5eb117f9542ec692f3f8d218eb71 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 2693129055c18e601962fc76273359e1094e4ed7..3f62041222f2131a308277218e9260d1e4ba5692 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;
 }
 
@@ -1000,6 +1013,52 @@ isert_handle_iscsi_dataout(struct isert_conn *isert_conn,
        return 0;
 }
 
+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,
@@ -1007,11 +1066,19 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
 {
        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");
@@ -1649,6 +1759,47 @@ isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
        return isert_post_response(isert_conn, isert_cmd);
 }
 
+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,
@@ -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 b104f4c2cd3852979521d02b514c6b7fa2a198fb..191117b5b508771bf7a4fb42d9423bb26f72319a 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 7ccf3284dda3ae623d23f459fc2652c0ce734f5f..f93baf8254c4d492065155b4b701529629260b30 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 66fbedda457128c8d2695575d8bf7a217d78abf0..e641088c14dc37bda98e95134b4235f151e3c0fc 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 3f3f0416fbdd52cb6664d56e54a14f8df344b589..653ac6bfc57a61147bbeb72fbc598a0d1884b734 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 01730b2b9954e21bd69208f51847b11f78246f5c..820d85c4a4a0f8c2b8fc813adfa30a07c529a953 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 ef0e5207ad69e3964c498df31b8bcec8ac19cad6..bbe7041212dd64e3ff934cc23c45fdee3adcdda4 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 21d02b0d907c1ada17aa3b1d0e13352cd2e4cbf3..6dc659426a51f5cca55fdbaf2348b3c28fa03dde 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 a7967ceb79e6f20336354c14ae9511eb3e79c20b..785675a56a10f8117b052ff06bf4e9b462e720b5 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 b4f0e28dfa41d6bbff0314783360d455dd6c45ef..eec0d3e04bf578ab6a6afe36e1c55ad5d4b0c969 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 5b19b2d6ec2d337d370481af750b2c7c46afaf06..f71673dbb23da174cfd8045b0782ce38cc4b4f3a 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 d8f98b14e2fe97ec7dc4ca2e5a48877eff3d05a8..fbe9ca734f8fe3839a30dcf805b159faad3cc225 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 e02e5d71745b45385449a9a3bb9ebf0540c36d64..0ba3766240d5b7e37ae3f52ed8fb72a8196865cf 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 cd4ae9e5b0c6bf20bc485c448ca00ed059478ebe..f4003d568a923a89d7f766abd77718f03cf1e74a 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 46d87569073951c7c63cbd13a354e9ff91a0941f..d14725984153b149aa6946b8bff8d8e69f30d108 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 2065ef6a949c15b2d5795cf1b96782724f3809ad..e65c41a7366bf1f6887ab5a5315622f1e1341478 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 8d0c8b3181c510b2a4935625a1071176952a24cf..70bdf6edb7bbb311bdb386535356cade99abacd2 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 b66d4ae0689871dd957599cebb0d4c1e20a81330..a5438d8892454971b07b1f917f849de0e3e56f45 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 d97059550a2cc328fea132189b999d85dc62d887..1846e7d666819ded083bb366ed20bee1e01fafa8 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 3bfc8f1da9fe75daebda0ca2c5cad26dc4a9000a..30b426ed744bd20de9766b969c9837a292622b85 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 1439fd4ad9b1ae95e9cb7e25f40172535302222d..5ef78efc27f2812155b50aca064e1a5679015f8f 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 0387e05cdb98b9708bde55143cd8a5cba853a2fa..5227e079a6e3b27afd71bcbdc2d03fa01e211ceb 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 df44b60e66f289880c177e98d78f1aa04ce08e7a..0df3ec085ebb49705c4db91815eb8df90808703a 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 7fcf21cb4ff869dd636c91ffe2f8248f0a1d17c7..c80a0ec5f1269b40be7da133c68c6e789c5e5329 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 aa04f02246421f503c63f267d1f0604454ddaecf..f1b758675ec77e2e2c0d16246e2ba772fff01476 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 bdf26f5bd326011595f8b9801cc2e408af6842cc..5adede17ddf6de2ffa7724aa8c72dae623f17611 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 1ff252ab7d46a1ed55fb98a93426acfb764998dd..f221812b7dbcf0d3bae7c5171fe9e184c781d7d7 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 b948fd864d457e9ce857d1d04fd74bf8997e0aee..4b7941db3aff33223481464f24a162d101ab7698 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 d5370a94b2c1308ece53dd50ca5f9a5011b25fc7..9e39d2b64bf8f3cc4a864e300ff61f5020b67dda 100644 (file)
@@ -116,16 +116,30 @@ EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo);
 #define DMF_NOFLUSH_SUSPENDING 5
 #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;
@@ -154,11 +168,6 @@ struct mapped_device {
         */
        struct workqueue_struct *wq;
 
-       /*
-        * The current mapping.
-        */
-       struct dm_table *map;
-
        /*
         * io objects are allocated from here.
         */
@@ -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 fe907f2e8f596e816786712bca6fe70ccf4f4b35..30779498c173fa846af6769294c94c44c7058e0d 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 45ac9eea488271e13f910a176974a9a6f47e1b22..a142f7942a015c86da5a72f7401232c58a0ffe0f 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 297f1b2f9a3219398087b12b8a7344e335e4423f..086262252230b98475eed8f6e0422e51e16b99e0 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 cc1e172dfece66dccafe3dc03f27a4957d85ecb8..c7dace671a9d13b8f8e42b661fca57cdb34f2638 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 a1a3a5159d71f1ffc3ab244232bf68b6877d5f50..0b4616b8719594560a70a1dfb977a206de5eba4b 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 335a8f4695b4691f06a8ea589dc4b0e2ba9b014e..886da16e14f23e16c0ef12c8b5a9e225e76820b0 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 2099f21e374d6cdf4388d66e8adbc2da43460271..23a0d05ba4263516a955b3208246778b9ec96342 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 a54182dd0e91d918ab6eebd4bd4151531100b9b7..90536147bf0458c444a59e176b79ddff09471f4f 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 e6667189ddcebd8134bbaf52a6fbe941140966a8..f22eb9f13ad54622b4618bb8adaef4ca6ef22704 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 ec24d71e153dc9ae3caa3c70cebe3f3edcf9418b..082014de6875ed26a800bc15844bde5a0199c7f3 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 b8424f15f9a678113117e01db1f4059361fc01b3..bae9c71dc3e9e986acf2e54f0cd79b55e1edce77 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 117a56926dcad041316a53f4ea47ed3c7263505f..93596e0e640b2a084f65e591c7be6ab3c1107f81 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 cc278b3d6d5a4338e7c97685f4e59c94f8e351cb..3dd5714eadba579c62e347718a073db83889a13a 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 8d26ff6eb1dbbf000a4bd2eb5f8e54fef1db2d31..139264d19263539bf68eef8c4a919eb3756b7b19 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 f981d50a2a8c0ce7346d13f57de7be5269f53f63..b2cd8ca51af74243281aa7cd14e3de1015c8b472 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 720f42d9d9f44aba91f52ddce09df73db007d3b1..dc20653bb5ad9d68cfa13e675fd21917b056bd46 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 58344b6c3a55ea19823553154d5c59294b268865..ba4364dfae6687a8ec60325b698a06e97fc87513 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 ef75abe5984c38f37c0025e9e38b85a8d45e44a9..873fe1949e986fb513103924d5377d7e5d219de4 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 6bc01fb98ff8bfad5c7c6e173d78f6151b6b3277..04bb29720aaf1c7bae4410cbb8f0b608394d0231 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 c7640fab5730d8dadcab775129ac894dd370e6fe..b88f3b3d5ed947c4e406d5c2a4792bf3af2797d9 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 afd561ab190d50a09789b6adafa92c38bb8294a4..d7d99f1c69e4f9459d0515a9eb8769dd182900c3 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 56a1fa4af0fec8d54be4303714eea29819cdf46e..6f738d8e3a8f3ef708451ba99df2574c1ef488fe 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 9fc2b985df0e191e4a0b7f908180b1e5d6ca6c5b..7606218ec4a760bb14bd5fcfbe0813e480f89466 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 3dc6098c7267716ddb2c05e9d312247dd8dfeee5..558f19154eb9cbe17365ec05c862b540fa4627e1 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 31a63c9324fe245b1d981ae124836f20fd1d17c5..1d675b58fd71bae6db5f5c80fd971745b0525fb6 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 fd47465e4f6a9f506771d729278444b1d131d66e..c14e66756b98471e0e3833303bd996b272895cac 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 58d523f2648f61894ff8ed98526fff077da79e91..301084b07887e9e13fa11b7772ff81dd85ed553e 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 377bf05b1efd20a3dea2e4a048fc04c44b2f5d6d..369cf6ff88f761104263b5e20cc1422f9a25da27 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 7e5bd365c2391dcf94359b78d25c9b85a672ccf7..7fc163d0253cb46592ed24b2409a5847524fe8e0 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 905320b67a1cacc01537dc7de04ece8be524e3f7..a8bf10fc665daf071b9dc0842767b5dad4fd9fab 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 1d2f7c8512b5d7b070abb546d44aec627b5b923c..34b76a9e7515be4bb99789427c1644d03fc313e1 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 b293912206ebbe39e3fa2fbc5aec53e88ebac6f0..27400c16ef9aa635332c0b8e007b9c40b4aabf79 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 12fb9b2eb8873beb009debf001eddf4b6f35bf32..2e3771d5735402cd58bdb79cc62b450ba95b27c6 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 bd4ada28b490ad40619ca21de690b6cdfb84f9f8..37bc04217c4457cae322c91ce8fb9ed3ece6167f 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 9ae977b5983ae74943e98ca3ef25e6005aa6c22d..e6588ee5bdb01e4e1a1333ba614e122fe7a194d8 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 8e2f79cb045eabca9ce1686ec853723097daf4e4..82bf5679da3064d5a8ffd9da91c3d9e085d8d8bb 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 04a6efa37cc376eb2c49637b26a499da8665439b..c3e94ae82c03028ff48e9eec1719938b8849e8e0 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 39f50fd2b8d2b570444362838ac12305e6b1a2a9..bf476358704da8fc1f8cecc626fd285c62227a64 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 0b899cb6cda1904b6f07cdb924f94be3d76ccb56..8d870b7b43ff25e9b9ee6042ff88aefe04d60276 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 54a9dd394f45ad530a4f3eae29c604f6893b359a..8190fec6808075049ca2e1f94d47ba3613f40602 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 8edb3d8f7b909d614426b917f9a31a173d7d3399..846b15f0bf6458d778ec731442e0e45107db179c 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 28cf95b372854f532bd619d558c5a3fbbcbd0cfb..4734836fe5a410c8cf4249d9c455f5ceaf4b627c 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 2e189d8b71bb218725b76d894172420d30bdfe6a..796463466ef07ebd3707821c30c3bb5e0bdae427 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 3f415fd12de34c76d4f33265fcdcc169edd852f1..f74698cf14c94d343e8ae1861bc7d730ff139b60 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 3f356cb282567e882361b7958146090d9092cb43..60c6f6739560ee105a1a1931c3d125d27b548ef2 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 8554b47f993a373f4f1b5558d5055ae3a45a197f..271d0b7967a6f3f7b875a2187352de690634a5ac 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 b0cc927e8b19c5a7ff4211e97711954a4ca5147c..faa64baf09e8b03297877dbbf73d4109ef6f5b4b 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 617ad3fff4aa2c4d355747ed703b92693a4bd5cc..e8a1ce204036f45cca1d1d495f29c8c7b72942d5 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 9eac5310942fd97b503290a1a2f38ef09cb01479..825ea86d982d5bfededf301d2e0d282ff1379cbb 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 6f3a9c00fe6512092c0a4789671cc08144a54277..8079e26eb5e2f7c4c5dfec7b725e5b0d061cc33e 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 bdf5e3db31d19853b53b9ba5bee14a8eda46f334..789c02a6ca1a3ee46f775d0212209d103bb1c88c 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 b4e1ccbd87ec630da2f8c3afaee95c7857c06a2a..70bc72e795d04b30814e32eb599f3b42f1de4328 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 51cd4c8f052036bba8c49be3390176faac73ff3d..ac43e929a1d6eabbc2333676e088c133fea2107a 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 52c717d977c937aff0e39c7194bf9089f0648c19..7fd766ec64c8d5059f01e593dd52c6479ccc21dd 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 8a47ac10927f0b172938d05e9425925a8da4eae4..264b755bedcef417eee59f3adfcd99704118e278 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 cf3a0aa7e45e699b9e4ad597f2d0ec429f9a87c5..401ca114ab99cbf43a4145b1b4c2d3fdd768b932 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 2c6b65c76e2b9ad3ebd60cf18919a4640de88bef..f56c1c88b27d6c0de3dc6536ed2191511ec87a57 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 d7d1670e0ca38db88dd1d93d55bf849eaef83a64..606a4baf944d9668ee9c1337808369f7b700e0eb 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 cae4f46838517472f4f705267ed9b3e93a1999c1..7ac7580f85c9ab6335e90c1a5c379d33571c0395 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 a2a5cbbdbe28e54ce3ff1c39617384a39b6d5340..1d384a371b41d6c82e335c617ba1a683992ed8c1 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 dd908980575716580567e52a16114bab3cdd5b99..df97033fa6ef3a0386900b029df456fbb1957401 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 8bd4e0d2ea03fffdcd662a5e06042da44d21e7cc..de3605df47c551428c082ddff97a4afa3aac2643 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 26a15b87a9a25be5b9ab1283da80c5dbec22c5f6..47d18d0bafe7b51fae5b2775c15fa70b19a3327e 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 a7256b732804189af09a2f7f0356dedef914ec0e..46f431a13782800c04198547ebf906394086e20c 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 a295e598486f71f40b57b77aaf98ebd7d7941501..f9f95f815b1a8c80ebe1b51d055b0cb28cd6f81a 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 e3168424f9ba5350d51c696e3a0d4714f94626ca..6c6b1c3b45e3e3342d0fc2f0481ab2d13d8da0f4 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 9aa56de69eed49e1ecb746e27998611f7efdd1d2..0a5c5d4fedd6e375b34a1848f3b646a6577bd97d 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 991202d4bbaec251ce6b93d48aabc2b652fcb196..ab01598ec83fefb759587b87ae905f8a8c3174f5 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 713d62e349f67efd7f125929c04f62430e474492..7f2b3c8926afbfade0fca5c58bea1e9356dc9d3b 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 20ca62d371c165ebbb7da2a68fd11ef80ab8578e..e968c3fdbd9e8e63b16982ba0111401c3b93ad4a 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 6b33a972c83ca1fa2c4ea275a9376a288deaf8ed..65d13ff1753630eae190cc446e7e39bcbe0ed94a 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 012bd62711242a03b061e8e387d648532ae8c6e4..ea76863dfdb44e22bb265d3ee6928a0611e60f63 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 1f9ec3b06b4e7946f2befc1f71115fdd2771d891..7e6d978478747641f56e5b66106bcc915e756671 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 bad90b16a6dd2f8117c22852d5140d9f4f95a22c..ab54628d9411a0f97fe75884ff176f2dfa164253 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 38cbea98764c901924fdce080abb76569605b9d0..32d82320b4854658702bd662820ea3aaa82b22e8 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 e9d95bda2ab1066a98c1b56d06e505322fe50ad2..ae9432637fcbb7d3e7777a2e9918ed4b37c37efe 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 28b5121881f5792397ff0a674220caa4b4d7108a..72af644fa05127f89548b9782cee62367823d445 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 01441e35d88b5415e28470086072aefe45221366..fbdff8b24eecd7d7b423b25a8ac4962e466299f5 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 3d5b06a5c308c9db906b995bea7830093cdeb655..bbe1a99fda366247e2d9d0b7598a74ca0a460761 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 38757217a074f20eeea1eca7717a6ad4fef9535a..30a8d75771af9622ac006c90f2dd660346af0dab 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 c4339556a2eae8cf09d187172d274c42aee3c1f0..0a2dacbd7a6326286cd1750b70ae174150163b63 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 809a75a558eef32b2e7c3fd32bb2ff536320ac13..ef87f7b09ea27e101fd6931327cc8238b33c8fec 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 e0634c8b7e0b4a8a8d564112bdfd04728fd54a69..d76c53a8f027b851e640af633b54dd04474536e0 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 ab8f3fee7e94463147dff499ad95b39a204e4dbc..9c6d66a9868f7ac30955dd369340012f6d74084e 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 485159a3c0b72f1739a7cd12feab3d6453910a1d..89c0b13463b73354b3fa56ce5bcc57b2fe989613 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 027809cca5f5be7ad74954cffaff7a0ccc2b5d2c..a4e49483de6a2f0e77820591c85e114f603d090e 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;
 };
 
 /*
@@ -534,29 +531,6 @@ static inline void tvp7002_write_err(struct v4l2_subdev *sd, u8 reg,
                *err = tvp7002_write(sd, reg, val);
 }
 
-/*
- * 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
@@ -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 c5dc2c3bf2d7ccca946aa47cbde481e3de141b2f..f58607df61930b7422b2e4ac25a9a5d84fac13b6 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 87880b19d8c3fcc633a6338f04ac634d3acf1929..285b759a5f7f11c74a9f24cec7f1f58bd0ef9b60 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 accd79e5a7fd8a4a7901d5bb010f515e6e51b351..f6bef25bd9ce8dacbc392046c6a04d6af5096422 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 3af408556d27f0ce5febb353cb49f5fab14e7dc5..081786d176d097327d5e5fa54553087ae7eea92f 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 f0a09214c519105bf4cbfea87f2ca6937dd88374..d248e6a12b8edd67166cc7d3d62f9bce50e6a09e 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 343e0215f74ce6dedd095ad7300e64ec69e7a791..3a152ce7258a7e2feeda49300c1dc9ac2fd05f4d 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 e71f139695afa1f23405f533d206583100574da8..6a3a3ff7ee6a8b5ba68233ee6f042ddd19e6529d 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 2f67b4c5c823bf396a4a2d17ebdabde113eafe6f..ece90df6a04359255aaa98969a7180263445be5a 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 f366fad6269e6f2001be0372fcf3ebcfc7791d59..25bdd9312fea5a0f1de997632fd02e4e9b6a8ae1 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 3bb99e93febedfa0b895e25c8eebf091b581b945..3be73f6a40e95c9c121c3edb97596cd149cf3b29 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 27c27b4ae238516b89f49da8627b1fbd0568985d..3f584a7d0781b9860aad6b6bb9f6ddef4ad2b449 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 1957c0df08fdb5717acedbf17162774f8c75dd05..d5a7a135f75d39d5bc2f6fb3366639dd6dc7ee34 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 e1cd13283407ce65b0c64345c9732be8e75aaf96..cb30ffbd5ba8d534daec5ceab6d709d888844bcf 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 06231b85e1a90edec58c8f76326abdc0802167cf..d12bd33f39cb3c7f322a0ef4d2965d1ebfa542c6 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 d4e2ed3f27e5edd45ab63caf69e77c2364e23a43..53196f1366f30d915b8a06492d7640200970f435 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 44f8fb5f17ff49c9a6fadc912d9d69b278ea5be7..447afbd904a4bd9dc3ca1f75169083798b879e61 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 b7dc921e1b9113f6777735af1f337d3430b41fd8..e564aac0aa30fc67ee3eeb9cca5ea7f2dabdf6d5 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 e7d08841341141b67871d6916f570c76ea15fbec..c6532de0eac79652b1bbf6fefb8428cdced46fae 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 6139ce26dc2c63039bdf27261eaa072cbe6979df..df578efe03c9a7d4faa6cbe6410e9e83e94f863f 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 38b1d64ffc27670a29078683f0630fa4031a6402..c4890a430dc6897776037bec175e3f6a532e0be8 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 e9c69d9c9e4ad41d7f1674337f05ddd21e958f77..4c559e86e340b39f2727794144ca4fd55b1ac2ac 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 aee7b6dacbfe26e355b855c7eb2d90c82cfd3abe..1110bcb14e2f680a9436b1af21a21546bb2413b2 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 6dea11a7a858f08850887a1041f1f4af0f2f3944..e3fc2c71808abbd0746cc7d9faabdfc14b9c583f 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 acdb6d58db5844494b6c47cbf861b15acf70937a..271d69d1ca8c7c0a4c0796151353e97c4961ab3e 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 a6080964a9eec3c366e40e846d6a74fe5507e056..92d9f077436679d0402b416a70384e9775923f96 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 ed08c89adde044ff22e6cbdca2efbea2d30a7c6a..e33d1a7dfdd09ee253e2d8160bdc31206f292c2b 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 fa672fe410793568990bf36d0802e9c646932ff2..2c951dec2d33988688d53ffc82610119d3c99ec8 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 a87a0e19593e7e3922bdb93d424aaa520c53778c..e18a7ace08b1b1a41667e10e5eb47d31f07deb91 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 c8f3dcc579d45136c730eb03f4b1679bdf6d6a2d..ad59dc9235aefd1ec7241185a70e9b4af6d94247 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 c7a9be1065c0b2d907a23dba31d5861201a96dc3..ecf21d9f1f34bb1e587edbdc6283a177ceee595b 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 51ce2c0e8bc168f9eae0e565782cc663f8b11ba2..afe0eaea81b4741abe477ba2bf337994a1e234d5 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 026767bed5cdae844c286d47636431345f81e538..ab797fe466d2dcd6d389f3ace68e77ec17021bd5 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 b809bc868a9f01070bee7cc37e1a85f1b73d888f..c08ae3eb9554d46fc29b4dfbfbf0f314c8b90cec 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 9cbbce0eaedca38ac1cffcd0d5d723aa41699af4..807b275a847e696b762c10d083874b618d30ee89 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 6fe9fe5293dc79fd1c5154c0dd52dd8a543793e0..104914a5bf06ebb42a4c073b44c4e8be35b6b4b4 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 932a0d73a7f8f7d40b5d447f9d88f49fb60d6b4c..801fc55b61679a944c43e6616c6fbf36c18cb5c6 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 07aa887a4b4a9ed46b9daf136e37c36ee9bbff9c..07a20748b707ef5356bd40fac96dc891d974716e 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 2290faee5852f13124d83503538fbd8bc6cd59af..493828500055297328376740a4e2a58d40a57a16 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 e9211086df490c1b7ec9db82f7ab74d82f4fd427..75ce14229e03b6e52c70bcbd3f67cc44bd3e8be7 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 f147b05bd860254b1dfccabd679f06c28eabb76a..8ac4b1f2322d7e63a6632c640e45497f3355b32e 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 66a70814004c32ef5188ef6ff9a3d3fc56a638d4..3022eb2a792503bc065863d6209c38a9d30d5014 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 cc409380ee168c861abfc45cea2660b95c819b55..e12bbd8c3f0b8da63f8418e6a00bc803f883963a 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 d2ad16c1569a8be6120420549403706748ce1195..8d1453a48014f6a2e29bfabe77d63ef763fd535a 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 71e8bead321b25774f5699ac15cae6ec6cff9212..33abe332d17599936c691eeeb2e4f836d6bc5d0b 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 7618fdae811e3b28264de314c43fe8c6996a8ae9..d37ee37aaefe5e4b681f402842cc33c49ddd8cb6 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 0b74fb2300dda8c74a01f3e1b73f901c47207bfd..9266965412c34d0c7020dd913bdd04813fdb5829 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 da224eb39b95a002e8aa2c3c2b2c91e9a4848ef0..6e025fea25422774ae478633c7038cd978c1fbf3 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 437284e747c973d5a3025eb1c39e989313891a08..8b29e89903014b4fbf4b0ab9a0f76f90f416280c 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 7005695aa4bd26cfaffc4edabb33420412321ddb..77edc113e48520228b587fb2d092e94f0ccfb54a 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 1f8b1bb0bf9fb39b9881d9bec07e9c604d913e9f..0ba3875af22e1cf06f675e37ad15f43ad4fa9bab 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 98e524178765bb3c1e6094e43fb7edda621fe3ac..0acf9202103d8b130067469240f4a8b3675da7cf 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 bb53d2488ad08be66206b9aa478fff2f91068a0f..923d59a321f8a9e150685447ecc12fc54044ca24 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 d133c30c3fdccbc21fb54b3f08b66966835d3565..e7e9840c6c35f4060835250cfde4d018a5564f63 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 25eaf61b98b487dd2c421c1f1b3ae337bfa7f6fc..08de865cc399331e67098cee8cb31667e9aa8b9b 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 0e55b087076fb3d29eb376d60bfff92c72e9ec90..7f838c681cea0ba1743d858a6982a35a724ede4b 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 01b5b501347eebdb5a540863acead54dba2a56db..15e9c2bac2b1bfeabba84e6236bbc6781fa2ab49 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 9d1481a60bd97d5ce60e8387365a7e22cbc50016..df4ada880e4215519b33cc81ab3cdb5d2c8e6dce 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 f3f5e43c1ac23b2ac056ab598910c745d19320e5..ace0bf0a3b9cb245a5399a55ae7acd2594eb1a1d 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 d0b375cf565fc9c384a5e7e93b16864b7c48d8ec..e180ff7282d9eb7f5aa556ba66822482b91adca8 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 396a51cbede7711f9aa1977539a261ec74ee7b32..6ed82e8b297bf7861847f7bb9ca085b728c36810 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 ea82a8bd28030f2d47322e20aee5237a99e2725b..cd08e5248387038f333eee4726775b139988973b 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 5f98df1fc8a0f315665e8865505d8554b88e3ce3..5514175bbd072ec92b9e4a1a472b5d00e3f51088 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");
@@ -1873,66 +1861,6 @@ static int vpif_g_dv_timings(struct file *file, void *priv,
        return 0;
 }
 
-/*
- * 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
@@ -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 3d3c1e5cd5d4c63c1eb23b61be1574296ab27885..0ebb312603690f39ccc102eee04a8375c1ac4e36 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 1b3fb5ca2ad47f8b4c339846e9e6dc5dc533293d..e6e57365025020f746e5958b357525e8b9a7dfce 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");
@@ -1517,66 +1499,6 @@ static int vpif_g_dv_timings(struct file *file, void *priv,
        return 0;
 }
 
-/*
- * 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
@@ -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 a5a18f74395cdfa80a8f5e56d314f949afcb9f84..5d87fc86e580ad367e8264a092b907dd91d03fd9 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 33b5ffc8d66dfe136e2cd0df4129963b6c60ad79..559fab2a2d67f456f5c144c8decbfe6590c43a33 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 436a62a995ee342d2c51d2a7e2273d299f24fb3a..53ad0f080179721dd97c333a051ce034d948e857 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 f25f46377399daae5e2962486f7e5cc7f3af9809..c2ff29ba68561302c1c9d78c31d6229fa63e8bef 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 528f41369364df47584d696e6c586df2e56e7be4..fb27ff7e1e0750e33215b96ee100c9ad569fd9dd 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 379a5e9d52a706921883c6a7c6078c2a2586fe1a..6489c5160ee8aa8de1332931b38e17705a7d4f71 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 539a3f71c16a9d8b0aeaeae6621937817a96386f..3d376faec777d1781434cdbf5526301f50b98271 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 c397777d7cbb3d0c8634a212ef8c546c3063edcb..617a798d92352e30e5342253f5fcc83aa6b18a5c 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 53fe2a2b4db32ad3cae10b1fb688d3cd274f517f..c7e7f694c6ed67328c60e8685d7c07e480853ed9 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 d05eaa2c84909cd5b78430030b2baeef005335c9..63c68ec7cfa44db2ad386bc26a9fa7f96b9b43eb 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 0741945b79ed08829d0fe7490771a9f725f6063c..967f6a939340ea7ace2eb8826703bf713be4cd9d 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 d7db133b493f7068e9f5281af8a2c95b9c21bf50..61bb0127e19d525835ce75d9f55ecb848762354b 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 7ede30b5910fab78b8c70bf022c565cbc5ab6021..cf520a7d7f712abd23f1c553607ddc5df410a665 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 800aba7ab4a7871f8a37c51846a5ad41b28224a7..03bf95ab017bce6be66f07a98141e562f1b64abb 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 8cc0d39a2fea0d9991123f6951813f8337bfda37..72a343e3b5e85e62393f8950c3d0e096d09b8909 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 390383941c1931fbe1a57bb6de0e0990c4d97991..10a7d7bbcc273a8b4ad0c5a11fbed757e8ee7d07 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 14bb7bc8adbeccc9adb4cf896a9c83f48899af95..08fbfedea90fd59e705b244b81442a4515e2403c 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 47da5e04924775b385c83cc3ba3c42027eccc261..7428b2d22b529f97720fd7fbc0922ac4e80c6b22 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 bde1f47f7ed393652d31ef71b0633ac642cbf23a..8d33b68c76bac7d9e278785a8c914dddce602197 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 f079f36099de76909d6967061c9266a91e728716..1db8cb4c46ef0a2c67e6525f4cfbaea2d3b13d7b 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 15ef8f28239b797df583fa910720847cd4e14947..19f556c5957f5661bbc5b5ccb35575d6e01b97a6 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 44d86b61d660b70608621da532fa3904dc761c6f..62599fd7756f5ce05c4a4ba23d9beb3f70abea2b 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 254d70fe762ab3b24367727afa62715229fb9e66..0914230b42de55ea531d63cc10bce844d1282ed3 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 3a6a0dcdc3e426390fa2b9ff2ab9edbcc9c47b0d..221ec428a01e75d0508f83660a92d9a53f6fdc5a 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 548236333cce1a7d8dd2132162b22499027a3dc1..f1d192bbcb4c42296c6dbb2e3549646403f9f368 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 7585646495892ea9693bcd73b75337b2a04d2e0a..540516ca872c53a05d3bce4dbcf3cb9b3a87b4e3 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 d030f9beae88b6bb37130b0ab199758e871bb410..1f079ff33d4b94f7e0bcd92edc2f17504952fe6b 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 64ab91edfb812c3f0a243201399be421c3230f51..0821ed08c122855370d3dd338e8da2f84cbddfad 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 01dec9e5fc2ba428029a7900d6ae426fec21716e..520c8ded9443f5869e101f8ca92d3c3346e9894f 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 c4c17fe76c0d5e0319c11947d9b7e062e3014b7d..a634888271cd7a38ff162bc56d4b97b88923e09f 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 4cc7f65d7d76d3ab32b205bb96bc4886a1744b75..6a17676f9d7227063fd4d22d9650d752e2695ba1 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 f7440e585b6b7bd927a52882eda1abc2032878be..c690435853bdaf69f80d79567cb8f2ec8af967b8 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 d338b19da544c92e8e1c73c66092ca96575bcb59..dfd0a21a06588b26ee7ccc290e59e9f853175ea2 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 debb44ceb1856888420226a9f6d4580c1143ab53..d2b440c842b3f0867fbeea30dc12efb9761ac370 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 c4395956a493a3a60ee2961407670573f1f9ef39..7f6f79155537a9fbdb921d516acdac9ca073d59c 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 1d7dbd5c0fbab03a88f63e74d9bfe0217d695c06..df3a0ec7fd2c68f83bf2d287efd7a75378766980 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 60e60aa64fb461cb05799ec72fbe4f67e0ef62a1..907a205da5a55d977fe39e40c7b612315578e996 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 c5d84c977e2918f4a1ab774428080e4d29b20fb1..e71651429ddad36523943d4f61c0ca89caaa5bb9 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 783f4b05b153703ef1a7504743102f0d41617803..6db245d84bbbe5f8e27bc9fb1555e2bdf0f20d0d 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 908dfd712e8e3fa809637962f141b76dd0768571..3e048ad65647460dfdbb596f67443d4842faec65 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 8dac17511e618c84d27a9db8bbfbd7587f5c1d2a..a908d006f5277c2abe9adebcbb757ea699495fbf 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 70438a0f62aea113a97bb241ee3f9a8b43d40870..40b298ab87f1669682aea3c68c70b57703af043d 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 0d0fab1a7b5e70e53c9c875790bdb4c77eb68393..b38574702fe9eb50ae3b523af5111df2628b3763 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 1a3b4fc05ec64c7ac437c1e81104fbfc12c43b30..a9e3b16460b8a3b55e90ea9327210460d52e45d1 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 d12faa691af8fbb7f3e41f7c6f9516140067d565..a130dcdb7206ec7bb09c5181f3aa5d9b56c0f1e8 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 4e86626dad4b1161841970960f989c958634f097..1b34c3629858f13a1ec0a0c14221d23e2c62af3c 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 5733033a6ead94d252c1901ab1833323458a43f1..51805a5e2beb742d1f3372090085c3a3f0097d86 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 ef0efdf422fec8b9e1d447e853cfd04d5e590f8c..641b1f071e06a2b74796f030ddfdcdc80644179b 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 ab6f9ef8942332c854633024bd58399206cad61e..0afa90f0f6abfdfd8aee75981c147608b9c1262e 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 39b77d24b9c276b3ef1d0dff2b0fed6f4cca72c1..3dd762e5b67e8e53ff05d2fd57351c71e9471797 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 59a9deefb24253455d531c71888c08afd49c8dc8..aa4cca371cbffbd0b98613e9ac6d8661737b9f27 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 7d0235069c87ca61d5c662e69a3e9b8ddf572f15..7a9c5e9329f2655327c2c3d6a22e660a11728d38 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 b139b525bb16f002eadecb0e8764a6ee45d391dd..626dcccc37da38451b3c94ff7d81a1717a8f78b3 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 136b7f8ff10d4f17f5318d461575d61d36eba790..39186224c16ad2e4bbc84cf7d7bf17459b933374 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 1abbb36d0755ad1bf8a2074e2fa4b484ca4f20b6..1044856325017b61f8c7e29312d7ef0083d2c0bb 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 a3fd8d63546cf08bfae801a01f24d1b940908c31..fea3e61476aefa3a2fe23d7237f46ac8a08311a8 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 5bbeb43e453188ae44112e5fa183a885dd36fd84..45a0276be4e599f15d2fef8f05a67b6e2655e184 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 5da337736cd894548a5f281963af0c8c0a5fd193..1047e3e8db77c1e708d7d3b87006b57aa9a79129 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 9689a6e89b7f9f0fd545556e0facc363823d8b87..6769193c7c7bbeef27f723e98760f73ece8d0219 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 d665242e82072ab525b82ff385ab0ebed09c487f..d4df305fcc189e0abb3a2474cd7aaadc808658cf 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 143d29fe013721a0d2f37d6159a8732919c4e889..f2de0066089ad0093b1e9619642769ce59076e0c 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 09cb4fc88f3437ee3bb48c35f834440bb66b656e..05dd21a35d63589667e1e532342cdad81f13ef2c 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 3a4efbdc7668e30edfe74664809b744b56a1115d..2dd0e5272941079a80a2fa4cac0c366035ec4d20 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 1b7a88ca195b9d6b2f016c7b4ce924f4a20e4a2a..ceaddfb85e492f6551a4c12fab5565c3f5f28e33 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 a2f7bdd5104f684324fb514600c7a02fbe367e75..b557caf5b1a4791846361ebf8ac382c429025f18 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 a794cd6c44416fa2b57c6606175fff30204bc245..b4f9d03636e3e8067e7adefc50070318915e37d1 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 4c9ae767fb31c3739c08e82888b4ecb1ecbf280a..21db23b196bed15eb46af3d1214fe5774a74062e 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 adfcc61bdf0b7d096dd954de2ec1cd9866ac973b..6f4318ff0db36b8e9480955b5618f1d9c2db10e3 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 9dc8bafe6486a07243c546b4fc45f00ebcceb84a..9c9084cb99f7dd1fde0800f0325c58584edd9e19 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 38d563d625956a35f8beda12deb3442adc27f43a..036e2f54f4db4b1bc5c6f574e19ccde1960da9b5 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 bb7b143b65d17ec54d6f622fa2136bffd55969a0..0817964d9172dace61cc983dc417e940bea4a225 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 06c06cc9ff254ef767d96dae23ab40912c24d035..ec805b09c6086a8d79ce03d3229d8ebe7929e477 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 82c6c9475d7cc6199a7814c17c9f03315c8470d7..06ac69245ca1cde81ddeb5018fae23f84d84e397 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 aac0f025f7678c582a08fa5a8592f53091f6124b..a587c9bac930924cb013b660e39aed02847a95d9 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 a002234ed5ded1e7070a7221872f6776f2e47cfa..253f307f0b379bc5d57271e630343c0e0b35c8c5 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 5dec323f4247e36c039aa0019e573fa5fe95b2eb..b55012c11842cfd50e8062ff8477df07f010552d 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 8b82ae9bd686b5ccd06de9b3a62e0d0df48f077d..07aacfa5903dca6430bda96cbedd733b23d5a300 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 5ab94ea4bc2840e7ed6320f08f4ce8f8e0b3cbea..b1cde8c0422b424141b752263e09b3751194ce5e 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 4835021aa3b6c21239123e01a4ae05436afd41ff..1c23666468cf69223542b5f89f024a1201c4733d 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 0a7d520636a9a5a2ac2017ec5243c65b6b1c5841..cfe8056b91aa05106497d3de54a95f1982273e29 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 7f51d7e5f739432f39b8b98548c8e0f57620dbba..0935f47497a6f5af71f78ef819275f2720486183 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 75ac9947cdaca48aab2a7dd06805a6cf195be1ac..f6154546b5c0b3d9a70fad164b07bb5e3d27e134 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 f548db8043d4bb1bfc52d7739348ac72d45d78f7..2f63029e7a363675c62d17955a4d4c5fdc974fae 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 235ba657d52e81f2914bfe5631c46823477de6d6..89de00bf4f8201f2b187892c42ff7ade070f531c 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 13249e5a789163ec9efe57158ce377b9478f4424..27948e1798eb8bb3d923b67999e23a4b7fd46195 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 1340ff268817763290e187d7658647f4a8bac0d1..c02794274f516812e47f292f6fce60522a8fde0e 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 cd221474e1b9df06dd62779aebeb8653e3e00df9..990626101718c54369538c2391d9ac4de4008e46 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 5ad9fd61d3c887953e0512e217f1388c989dcf0b..e812119ea7a829cfe8e28c7130d73b63406f3a78 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 b638fc1cd5740fdb5a93e8885cddfe616f76fffd..1ea17dc2a76ed51b6560ae642c6f31301f4a57fe 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 b5827ca3a01ea811b2a7d47531ec420d16a292f9..a1c68d829b8ce7be68542ad1085dad46ce636b49 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 658c6d47fdff7f0fd2bf1bc8a2de7bc7a61a415d..399916bd588f709269fffc6f6611b3f87f8c05ad 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 e48cdeb9df41bd3ad5edfae9e6b00e1af7354753..1cb6899cf797159869f1ee7e24d5f3eab0a9788e 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 ef4c65fcbb734ce6852dbd30856a5f3409849e86..879c529640f7e20234ef3a40a9231223c110259a 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 efdcb15358f118ae3ebd0aae1aeb732ceecf1de3..e97964ef7f56a847081dc99efb278579090e6d2c 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 2cc8ec70e3b68cee498a850525973c771354eef3..c0cd0848631b22953bd09723aa722decedef8687 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 533a33127289d959f52e407b43ebc1c224f53877..729b3540c2f9b4fe28ffb97f59daccd910e3ea6d 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 91e0119e8a8702908badd7aecb8c14738f0a4719..ea2d5ee86576565930d0336605a6e20f6e0528b8 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 d1ddfa13de86d8a474796e0af2da49bdcb8eaa78..449a99605a87f615f3ed1c778ee5f01d296d2965 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 83bfbe4c980fdad90b23b952f739f038ef12bc3f..dc65742c4bbcabfddf54f8fdd9797d6bdf162a6f 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 a802128ce9c591e57cb7e35b20131e03b15e53e5..fc157af5234a3e2c82c83dbd3f6d498758b96589 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 b22f8fed81277d5cb89ec7d86506fc20d06718ec..bb1e8dca80cdfc88dff7919b70da410aa617d1c0 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 466b19d0d767a653458b313a057d9f40a1c86531..ea181e4b68c5b445026b5f75458f86a7b7096db8 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 622871db04aa9328d8e56955172c70d609f0673f..0e0477847965ad822b61ba005de3b34865910275 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 32d60e5546bcbd7ec474dae36a345c493c31165e..1a577ed8ea0ca0163e9203e9db0a143ccd65a743 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 a9323b63d8e5f0632f5f78f6e125d8b35397e4b2..205e9038b1c0d406989a180d059b9f68e7b517c5 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 5995ec4de6bc633f62f4a3f98d7ce273dc2e4e8f..b7ae8721b84788a842cd84f9bef7ef1592434371 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 ef8efeb8007072a66ed96488deddf01be82a04f2..ac0b11f46f5037d0cb29eaeb8896b445537fa76b 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 6008c8d546a32e925ed73ba346fb4233510822a4..a9150964356329d93ea136e151c0d7f0aebf8590 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 ead9a1f5851318d31abf985dfc5bb653e6b28ce4..f4453d52801b94140cc1201f437ba68fec694095 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 de247f3c7d0577746ebb27f1f725425024606b43..d73d9a1952b47ce77e74e95731e74a3d97c6b1f1 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 ae8f229d114122e838de598362ab431ccada64e8..6053661dc04bd39727021c311f7d80f1d37ca60a 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 8247c19d62603cd4fbf977f010e28ea92ba6b045..cb694055ba7d103ad75bfd73b2f41a0b0cb1e315 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 774ba0e820beaee594eadb6f99d9d79a17d75a37..4f8567aa99d8fb357f7337b66af092fa846caac2 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 1478f3d576308d51504fae89426568c501493557..dc685d44cb3e4ef24284f9807c966af7e85a35a8 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 e11267f35d87c407a0efb17b16940306f7e47a03..c4d51d78f837771eafd6fb170cfc4f4feb7a9734 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 91bae930cd794de38cccdc32610343a347624a70..41847076f51ac392507f6dec5722f9cc4eb72186 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 20b6ae0bb40d613c89614c655ca9b7b110a5aa5f..1e354747de3f361399e4af56636d1efe8f64c714 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 a8a65fa57930c1a0dd1e7808a22ffa0a015726a2..7c280f35eea9149bbc57dd18de13acce440d6086 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 2bc153e869befb7ab21df85ce809e2f0fde5efe9..8a917f0605035bd3c61b278b02df955ba8484c08 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 c957e9aa607783716201e41e6ddb8de0b38d8309..2cb44de2b92cb18513a7d18ec41d8838828c2def 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 a59153d2f8bfd11dbf1f3f681ef6548bd3b7ecad..876fc26565e3bc05dbfe4a192ffe916080495fb2 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 307d8c5fb7cd771654a1bc08d0c0f94f45c2d103..1ccaaddaa307874479faf08ccb56ecce76c76cca 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 a78de1d1bc9eebf24597a198670268239a2a09df..cc1aa14996ff04ebc75f4d8c050075bb34c7128e 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 21b9049c7b3fa111fbedb61b71782f7e699651c5..f8a60c19753476f53c87bf44b555031eb0e8b201 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 d34c2afe2c24527f04af105204b5492d7fe1b9a3..5c9e3123ad2eac4dbb98ae5b584a7a016849d38d 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 541c9f1e4c6a0dc0667597d527b2a0763ecdc668..6ed85efabcaad28d67f2493357176037317355aa 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 5dbefa68b1d20f0e0ca14fd725b99aafb9410fcd..81695d48c13ebc5ceeb5560a0787aae94a516766 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 b7492775e6ae29574f4db8ccc0bd94c715f8dd11..f552ab997956840c61f4a39cecd110c3469530fa 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 b2dc32623a71f239e2ab914acba6d99b84708bc8..3afff92804d3c003b986237e385bf4d7c04596ef 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 af505fdd9b3f73d581665f660cf622921bea64c2..9e35982d099af2e41ec762e1f16b36506ac5d176 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 aa50c46314b7456cdc43c565af2d52b5804f26eb..4c33b8d6520cbc1714773a83cc1a6da2f5edebbf 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 3fed63f4e02641538287cf244410037aac3b60a4..a95e5e23403fe3254673d30e323c2bebd389e1ef 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 f1295519f2853315d14095075ccb5e479653c14a..8f7a6a454a4ca72460ac7e3c793a8115c94ea66d 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 5923c5dfacd5ae8c8cb65af2499d42d149773803..c8859d6ff6ad14e4aaf0ba6192ffe9613edcea8b 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 8ed5da2170bf8f6e5a6f3fd2103e88eaa6282ece..02d1b6327117b4ba599bed35f56e9c89a6669943 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 7658586fe5f4607fa7487c10a312913103b19d53..68e6b5e912ff6221a0c6ca04231e3e4925f806ff 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 67f572c3fba2305c91d6ae3a33ea699b63dd9313..65411adcd0ea958a3b4c7a5edd6f4f2d57cb32d9 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 828e7c10bd701cc9b598f26721a413de7d378cde..9db674ccdc68c11b2751d290f786a6cf56d6a6d9 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 2ff7fcc77b1104fe7d1ca1a2a9d5738ede27acb7..1365c651c1777bd5f7973281f26baccdad6c8995 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 e3bdc3be91e12822bcf92c4538433522a2aaa886..9fc4bab2da97c4109da4d74dbde7d21a1168cd61 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 bcdbc14aeff0d40b4514b777fd7b4d27541cfc9f..8cf7563a8d9208b13c64d73b3f4ac59f5a849b40 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 37afb96833721675248d7f3d27adace2b2cbde4d..38fe32ef5e5f438d713e840f6b83332f19e6a6a8 100644 (file)
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_MLX4_CORE) += mlx4/
+obj-$(CONFIG_MLX5_CORE) += mlx5/core/
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 3de52ffd28722dd493d5a30a319bfaed9f372b93..a7aa28054cc142b7ab6dc99b64b893e925fc94f6 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 1df0ff3839e8f44e4125588009d20a74d41773f3..3df56840a3b9282c7ab308682d448bba6dac53f4 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 3a316b30089f9139384ef35b6424ccc6bd8fbe0a..342561ad3158d2660e2d08df349359530950ca0d 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 42d670a468f89462a4e31ebde531c6a0e9c3b644..3d2a90a626498d20c96ba7729beacec16b9b5040 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 00a71ebb5cac2f3b4a7b11248d32139db67a772c..9f7fe21580bbcc01a08ed1b9665c9ffb1a6c40f3 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 022dc635d01e4935ee84c0378e0d606e94028a39..3cd85a638afa6dac4a76eae188177acb7f8dec70 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 157a573096011a07d7e30cd40ce88166b9465c28..9d30809bb407174214e1be674b323b0dd88c0a8e 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 157e762c15714d3c03778edd6ae3df8f68a31bab..70701a50ddfa6276105f383b33c81d88e885db33 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 76e4c039f0d5db725871da9454631dc352f19213..d35a5d6c8d7c8219f5b142b82a02a8f79009a48d 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 4a05d0427a9cac879015684b51b1c803286ca4bb..07453bbf05e70f6c507b5ff1775f836518d066b1 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 795843dde8ecdf422718ab3cb2e54ceb18c43dff..203415e02518a083120c2529ff95133881645690 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 8c05ae017f5b38b128ca5fe1f1a0d0e599ca9615..c9382d6eee7861bf4a8bd1399cfb6180a1fb7273 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 01adbe0ec53b89af776957d1b4cc58038aae818a..74277c20f6a5e5601f7b5740e77eaf5f9c638fb9 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 8b928c67e4b9a14ca6dd94421caa95d1275995d1..587992952b3c390ecad450875b015fc3c45f6bd9 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 6bbb9447b75d4895c03a38af0e7066e9b32338ca..c710d908fda6a47d1667a0436b1926eb68b35881 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 6002d363c637ba0c6e1c7ca323df1905c214a9b4..0177295599e0cd976e14982b5991fef567cbe52a 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 8056eacba7587259eb3dfe6932b4110333bfd3e8..4f401f753f8e98b11532df1bcfd7ea1efa6c7d87 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 81471bf415d87fa313c72fde0b8d52176495aa75..d53e1b02e8938ecef1d54d66f8e4f3d74eb45839 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 03317ffea62c5683dfdef0a49cbe3b98dca99254..20da8f907c00cd2a322ef7200a9b03938e7a3e0b 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 d8b2c3eedb57f0da855bfb8207fd0fd01b905228..889aa7067899e2038b7feed545292bdb6a34359a 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 a079e5242474e1d621613ca327bcc2b0254edb2d..f7928bf66478df81dd72927de62fbad34b89c104 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *          Name:  mpi2_init.h
index 0de425d8fd70e36788f62044127b8407fd90c50e..e2bb82143720acb5634b96085982662bb733e5a0 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 d1d9866cf3005f79b43ad63a13114e78196ecbc4..71765236afef30c6c2092eee5882fdab022057ec 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 b4e7084aba31c464c63ddbb4a3f0ec967c62a3ec..cba046f6a4b4c0b6591da8d985c370274889484c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *          Name:  mpi2_sas.h
index 71453d11c1c182a155a8de7a866b34646231ab73..34e9a7ba76b0d0eb82b3c0bcb02039a01454a33c 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 516f959573f5921f9b7fada55f2a93d86e360548..ba1fed50966e2669d25dc0dce02aaf60dfe49241 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2007 LSI Corporation.
+ *  Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *           Name:  mpi2_type.h
index 18360032a520b5d7e5d424558c0f438a7fffe35d..5dc280c75325ba775f52c6e4269a4b4c6c6310f5 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 994656cbfac92068da9d0d8ec74878cdf35f0e24..0ebf5d913c80f916835fa42178af2e41815c7bdd 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 4db0c7a18bd8a4c6f27665ed991eaae8b956f19d..936ec039199057c489cb411622018449b406e2c1 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 0b402b6f2d26b34b486996e0fed738260b11ced2..9b89de14a0a3dbc8a6758525ed18c25463808540 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 bd89f4f005503903236b514b81587bbe04ea14c5..53b0c480d98fd628fa669cfedd6ea1ff2147f530 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 35405e7044f85f40ff473f4aadac2c50f9fd1560..545b22d2cbdfa244b83c3d86e68400723ab87772 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 dcbf7c880cb282502b4e0b55f77d317f3f0b4496..8cbe8fd21fc409afcbf5063b2cd45bbfe7c6ca1c 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 87ca2b7287c3e6e90cacbe777daeeb6a040ef8c4..dcadd56860ff9370bcb7721a622bb5ae21fd50a3 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 6f8d6213040bc7b327cfd55f5ab4bed74a844bef..f6533ab2036446929f6d1657757d0f0b4c923aa6 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 a10c30907394e8345e1bccaf45c25572825e95e3..bb693923bef1c5c02da64b48d49d6e88c0f068f0 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 e4b9bc7f5410fa5e38a9df530cba183652f1962a..3861aa1f45201965a69cbde2b2aad460c2f6ab0d 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 bf60c631abb56018235d0c177b9cb47f89cf7adb..d7a99ae7f39d45727001f470e169a0d835558907 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 39719f8924889c04d1aadb4dbe027dfdb8d8a87b..417eaad50ae23ab9e796ebe2f6b20685e61d8d8e 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 cfa2a20dee973d2f0df08f7ba47ac28de5822a42..df132fec6d86c98c29417c38f63eaf3a9df3e504 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 c32efc75322922460cf713a04771d2a0c4c55f6c..95ca32a71e753412e82b2dd87affe1bd05c9f0d7 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 026bfde33e67357b8149f0738607044a99a97b1d..2d98232a08ebe0a08a64a94c74c7c7b484786295 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 d0ea8b9211771a4ac0236373ba94d089460c62d6..0926451980edd6cccc4abf399466e9e89defe9fc 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 3565dfd8f370732115f3b3aa5ec6223015c73414..f2216ed2ad8c1af090cb30f5ce7a5e2c28b2391f 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 0a5c8951cebb4ef0e345bdf4b5a8fc1cd35e2ed6..28c38b4929ce64807130f61e9176e2f84d04c688 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 15e4080b347cd1ed69c9b905125d2001332d3ae9..42ef481db942a79685900c136e7140a199cd8dc4 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 d2a4c75e5b8fbc7f086877767e84c88bf49ea704..2d8e7b81235253734bd6bbf0041900ff92ba1afd 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 3587ec267fa6468c8cd51e86082f09e603c80477..7257c3c4f2d0819dd59601aa95d0c6ac8e5dbfe1 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 a6df55838365e2ebac0c15abe52cecb462518f48..d7993797f46e1339d4a36e05b88c6a49905c1d96 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 cc327dc2fd10467cfe46171bde6be2edcbcbcc67..1a092af0e2c353a5126e8cc8ca96f3c15fff3ec7 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 ad72c1d8511162b9465b96265510bdad6dfd1e42..3e21e9fc9d912f90d4129a6709e4e655ffc96e3c 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 fcdc22306cab84b386ecaabde8234362e555b922..83a8f7a9ec768b68af63c718447d7cb0d1089d01 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 66b0b26a1381e4ecb17806c935ca05c1b62cfe70..a318092e033fadd73c702eb97baf3d8709da5608 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 d055450c2a4a41d6d8f1d724104e184d37bbdaf0..cb4fefa1bfbaea58a03e973de770233f41f6b34c 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 86d522004a208255b17861b4c1cb556bbe7c973e..124392f3091ed7be8d04b370b375f82b3a677f0f 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 945198910460a8ebcb0baa049bdd66cbe524b0c5..83ec1aa85964c73c547bc3f3eb2586d3b6d73dc7 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 10f99f45a29bc8a567126e5739cd4f36ac5a9cca..89cbbabaff44c66771efc3f26b18e9b4565a4cc3 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 5ff3a4f1944310e1aa751cae74e30b3e069fd7dd..36171fd2826bff5a113b43262c7c749ac87492e8 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
index f64b662c74dbfca1831149642cfbcd861efa0de5..3227ebeae3f1c88a5260a672e090a31cc18fc8b4 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 1fb58a1562cb4e2d44571ea3baa592be0557e4bf..4d79ebe2de06d9b335333aee5baa060032454619 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 05673ed45ce4ca4c113bd221fbb6c3bae9da040c..766a071b0a224a4b7c6ad5b0a8c4139341981f5f 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 b2f4ef84f3db692879c229d6ec730958778a7e66..59540cd4bb98c0d14705841b6edbd35c50ad640f 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 5829360f74c9c9f6dbf2caed98059e43ee1743b1..ff48fce94fcbda376938d3482d44978bd65533b6 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 126f84c4cb6466beb8286af04055eaa93fc4a408..8e13bd494c980198d48942b88d400d8fb1a57ac5 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 ba913f1d955b04876387980aee81435ea9f48322..24d98a6866bb7d91178daffaba6e867a8f332a18 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 c32e0acde4f4f7518ef719bf47412c7959dc9821..90d6ac46935587fb905e910e39a7a52002888f43 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 50066e01a6edd1e86caccb9b2bd937ec97c6bea1..46ed8324503500290885268e36cd0587639c8b8f 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 0a2c45dd44756a514d9ab3f0dea5f3c5b82dd89f..4afa7da11f375cfbbf9e08f0df0676dfae62302d 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 ad00e2b6032380b26843e6b24c29e676a43b7bac..af65ea655f15dcaaee6e41405720120a52d7e8cd 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 98e2902afd7471a7772b840b3a79d4b7e3472554..a4c589604b028d7d74e1a7f895b6ab3aecbeac75 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 9493128e5fd2d7a743521781eddcd507622310a2..6e1d5f8d3ec1a7c02be293aa9ffd195d63ceff29 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
diff --git a/drivers/staging/ti-soc-thermal/Kconfig b/drivers/staging/ti-soc-thermal/Kconfig
deleted file mode 100644 (file)
index e81375f..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-config TI_SOC_THERMAL
-       tristate "Texas Instruments SoCs temperature sensor driver"
-       depends on THERMAL
-       depends on ARCH_HAS_BANDGAP
-       help
-         If you say yes here you get support for the Texas Instruments
-         OMAP4460+ on die bandgap temperature sensor support. The register
-         set is part of system control module.
-
-         This includes alert interrupts generation and also the TSHUT
-         support.
-
-config TI_THERMAL
-       bool "Texas Instruments SoCs thermal framework support"
-       depends on TI_SOC_THERMAL
-       depends on CPU_THERMAL
-       help
-         If you say yes here you want to get support for generic thermal
-         framework for the Texas Instruments on die bandgap temperature sensor.
-
-         This includes trip points definitions, extrapolation rules and
-         CPU cooling device bindings.
-
-config OMAP4_THERMAL
-       bool "Texas Instruments OMAP4 thermal support"
-       depends on TI_SOC_THERMAL
-       depends on ARCH_OMAP4
-       help
-         If you say yes here you get thermal support for the Texas Instruments
-         OMAP4 SoC family. The current chip supported are:
-          - OMAP4430
-          - OMAP4460
-          - OMAP4470
-
-         This includes alert interrupts generation and also the TSHUT
-         support.
-
-config OMAP5_THERMAL
-       bool "Texas Instruments OMAP5 thermal support"
-       depends on TI_SOC_THERMAL
-       depends on SOC_OMAP5
-       help
-         If you say yes here you get thermal support for the Texas Instruments
-         OMAP5 SoC family. The current chip supported are:
-          - OMAP5430
-
-         This includes alert interrupts generation and also the TSHUT
-         support.
diff --git a/drivers/staging/ti-soc-thermal/Makefile b/drivers/staging/ti-soc-thermal/Makefile
deleted file mode 100644 (file)
index 0ca034f..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-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_OMAP4_THERMAL) += omap4-thermal-data.o
-ti-soc-thermal-$(CONFIG_OMAP5_THERMAL) += omap5-thermal-data.o
diff --git a/drivers/staging/ti-soc-thermal/TODO b/drivers/staging/ti-soc-thermal/TODO
deleted file mode 100644 (file)
index 7da787d..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-List of TODOs (by Eduardo Valentin)
-
-on ti-bandgap.c:
-- Revisit PM support
-
-on ti-thermal-common.c/ti-thermal.h:
-- Revisit need for locking
-
-generally:
-- make sure this code works on OMAP4430, OMAP4460 and OMAP5430
-
-Copy patches to Eduardo Valentin <eduardo.valentin@ti.com>
diff --git a/drivers/staging/ti-soc-thermal/omap4-thermal-data.c b/drivers/staging/ti-soc-thermal/omap4-thermal-data.c
deleted file mode 100644 (file)
index d255d33..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * OMAP4 thermal driver.
- *
- * Copyright (C) 2011-2012 Texas Instruments Inc.
- * Contact:
- *     Eduardo Valentin <eduardo.valentin@ti.com>
- *
- * 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 "omap4xxx-bandgap.h"
-
-/*
- * OMAP4430 has one instance of thermal sensor for MPU
- * need to describe the individual bit fields
- */
-static struct temp_sensor_registers
-omap4430_mpu_temp_sensor_registers = {
-       .temp_sensor_ctrl = OMAP4430_TEMP_SENSOR_CTRL_OFFSET,
-       .bgap_tempsoff_mask = OMAP4430_BGAP_TEMPSOFF_MASK,
-       .bgap_soc_mask = OMAP4430_BGAP_TEMP_SENSOR_SOC_MASK,
-       .bgap_eocz_mask = OMAP4430_BGAP_TEMP_SENSOR_EOCZ_MASK,
-       .bgap_dtemp_mask = OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK,
-
-       .bgap_mode_ctrl = OMAP4430_TEMP_SENSOR_CTRL_OFFSET,
-       .mode_ctrl_mask = OMAP4430_SINGLE_MODE_MASK,
-
-       .bgap_efuse = OMAP4430_FUSE_OPP_BGAP,
-};
-
-/* Thresholds and limits for OMAP4430 MPU temperature sensor */
-static struct temp_sensor_data omap4430_mpu_temp_sensor_data = {
-       .min_freq = OMAP4430_MIN_FREQ,
-       .max_freq = OMAP4430_MAX_FREQ,
-       .max_temp = OMAP4430_MAX_TEMP,
-       .min_temp = OMAP4430_MIN_TEMP,
-       .hyst_val = OMAP4430_HYST_VAL,
-};
-
-/*
- * Temperature values in milli degree celsius
- * ADC code values from 530 to 923
- */
-static const int
-omap4430_adc_to_temp[OMAP4430_ADC_END_VALUE - OMAP4430_ADC_START_VALUE + 1] = {
-       -38000, -35000, -34000, -32000, -30000, -28000, -26000, -24000, -22000,
-       -20000, -18000, -17000, -15000, -13000, -12000, -10000, -8000, -6000,
-       -5000, -3000, -1000, 0, 2000, 3000, 5000, 6000, 8000, 10000, 12000,
-       13000, 15000, 17000, 19000, 21000, 23000, 25000, 27000, 28000, 30000,
-       32000, 33000, 35000, 37000, 38000, 40000, 42000, 43000, 45000, 47000,
-       48000, 50000, 52000, 53000, 55000, 57000, 58000, 60000, 62000, 64000,
-       66000, 68000, 70000, 71000, 73000, 75000, 77000, 78000, 80000, 82000,
-       83000, 85000, 87000, 88000, 90000, 92000, 93000, 95000, 97000, 98000,
-       100000, 102000, 103000, 105000, 107000, 109000, 111000, 113000, 115000,
-       117000, 118000, 120000, 122000, 123000,
-};
-
-/* OMAP4430 data */
-const struct ti_bandgap_data omap4430_data = {
-       .features = TI_BANDGAP_FEATURE_MODE_CONFIG |
-                       TI_BANDGAP_FEATURE_CLK_CTRL |
-                       TI_BANDGAP_FEATURE_POWER_SWITCH,
-       .fclock_name = "bandgap_fclk",
-       .div_ck_name = "bandgap_fclk",
-       .conv_table = omap4430_adc_to_temp,
-       .adc_start_val = OMAP4430_ADC_START_VALUE,
-       .adc_end_val = OMAP4430_ADC_END_VALUE,
-       .expose_sensor = ti_thermal_expose_sensor,
-       .remove_sensor = ti_thermal_remove_sensor,
-       .sensors = {
-               {
-               .registers = &omap4430_mpu_temp_sensor_registers,
-               .ts_data = &omap4430_mpu_temp_sensor_data,
-               .domain = "cpu",
-               .slope = OMAP_GRADIENT_SLOPE_4430,
-               .constant = OMAP_GRADIENT_CONST_4430,
-               .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4430,
-               .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4430,
-               .register_cooling = ti_thermal_register_cpu_cooling,
-               .unregister_cooling = ti_thermal_unregister_cpu_cooling,
-               },
-       },
-       .sensor_count = 1,
-};
-/*
- * OMAP4460 has one instance of thermal sensor for MPU
- * need to describe the individual bit fields
- */
-static struct temp_sensor_registers
-omap4460_mpu_temp_sensor_registers = {
-       .temp_sensor_ctrl = OMAP4460_TEMP_SENSOR_CTRL_OFFSET,
-       .bgap_tempsoff_mask = OMAP4460_BGAP_TEMPSOFF_MASK,
-       .bgap_soc_mask = OMAP4460_BGAP_TEMP_SENSOR_SOC_MASK,
-       .bgap_eocz_mask = OMAP4460_BGAP_TEMP_SENSOR_EOCZ_MASK,
-       .bgap_dtemp_mask = OMAP4460_BGAP_TEMP_SENSOR_DTEMP_MASK,
-
-       .bgap_mask_ctrl = OMAP4460_BGAP_CTRL_OFFSET,
-       .mask_hot_mask = OMAP4460_MASK_HOT_MASK,
-       .mask_cold_mask = OMAP4460_MASK_COLD_MASK,
-
-       .bgap_mode_ctrl = OMAP4460_BGAP_CTRL_OFFSET,
-       .mode_ctrl_mask = OMAP4460_SINGLE_MODE_MASK,
-
-       .bgap_counter = OMAP4460_BGAP_COUNTER_OFFSET,
-       .counter_mask = OMAP4460_COUNTER_MASK,
-
-       .bgap_threshold = OMAP4460_BGAP_THRESHOLD_OFFSET,
-       .threshold_thot_mask = OMAP4460_T_HOT_MASK,
-       .threshold_tcold_mask = OMAP4460_T_COLD_MASK,
-
-       .tshut_threshold = OMAP4460_BGAP_TSHUT_OFFSET,
-       .tshut_hot_mask = OMAP4460_TSHUT_HOT_MASK,
-       .tshut_cold_mask = OMAP4460_TSHUT_COLD_MASK,
-
-       .bgap_status = OMAP4460_BGAP_STATUS_OFFSET,
-       .status_clean_stop_mask = OMAP4460_CLEAN_STOP_MASK,
-       .status_bgap_alert_mask = OMAP4460_BGAP_ALERT_MASK,
-       .status_hot_mask = OMAP4460_HOT_FLAG_MASK,
-       .status_cold_mask = OMAP4460_COLD_FLAG_MASK,
-
-       .bgap_efuse = OMAP4460_FUSE_OPP_BGAP,
-};
-
-/* Thresholds and limits for OMAP4460 MPU temperature sensor */
-static struct temp_sensor_data omap4460_mpu_temp_sensor_data = {
-       .tshut_hot = OMAP4460_TSHUT_HOT,
-       .tshut_cold = OMAP4460_TSHUT_COLD,
-       .t_hot = OMAP4460_T_HOT,
-       .t_cold = OMAP4460_T_COLD,
-       .min_freq = OMAP4460_MIN_FREQ,
-       .max_freq = OMAP4460_MAX_FREQ,
-       .max_temp = OMAP4460_MAX_TEMP,
-       .min_temp = OMAP4460_MIN_TEMP,
-       .hyst_val = OMAP4460_HYST_VAL,
-       .update_int1 = 1000,
-       .update_int2 = 2000,
-};
-
-/*
- * Temperature values in milli degree celsius
- * ADC code values from 530 to 923
- */
-static const int
-omap4460_adc_to_temp[OMAP4460_ADC_END_VALUE - OMAP4460_ADC_START_VALUE + 1] = {
-       -40000, -40000, -40000, -40000, -39800, -39400, -39000, -38600, -38200,
-       -37800, -37300, -36800, -36400, -36000, -35600, -35200, -34800,
-       -34300, -33800, -33400, -33000, -32600, -32200, -31800, -31300,
-       -30800, -30400, -30000, -29600, -29200, -28700, -28200, -27800,
-       -27400, -27000, -26600, -26200, -25700, -25200, -24800, -24400,
-       -24000, -23600, -23200, -22700, -22200, -21800, -21400, -21000,
-       -20600, -20200, -19700, -19200, -18800, -18400, -18000, -17600,
-       -17200, -16700, -16200, -15800, -15400, -15000, -14600, -14200,
-       -13700, -13200, -12800, -12400, -12000, -11600, -11200, -10700,
-       -10200, -9800, -9400, -9000, -8600, -8200, -7700, -7200, -6800,
-       -6400, -6000, -5600, -5200, -4800, -4300, -3800, -3400, -3000,
-       -2600, -2200, -1800, -1300, -800, -400, 0, 400, 800, 1200, 1600,
-       2100, 2600, 3000, 3400, 3800, 4200, 4600, 5100, 5600, 6000, 6400,
-       6800, 7200, 7600, 8000, 8500, 9000, 9400, 9800, 10200, 10600, 11000,
-       11400, 11900, 12400, 12800, 13200, 13600, 14000, 14400, 14800,
-       15300, 15800, 16200, 16600, 17000, 17400, 17800, 18200, 18700,
-       19200, 19600, 20000, 20400, 20800, 21200, 21600, 22100, 22600,
-       23000, 23400, 23800, 24200, 24600, 25000, 25400, 25900, 26400,
-       26800, 27200, 27600, 28000, 28400, 28800, 29300, 29800, 30200,
-       30600, 31000, 31400, 31800, 32200, 32600, 33100, 33600, 34000,
-       34400, 34800, 35200, 35600, 36000, 36400, 36800, 37300, 37800,
-       38200, 38600, 39000, 39400, 39800, 40200, 40600, 41100, 41600,
-       42000, 42400, 42800, 43200, 43600, 44000, 44400, 44800, 45300,
-       45800, 46200, 46600, 47000, 47400, 47800, 48200, 48600, 49000,
-       49500, 50000, 50400, 50800, 51200, 51600, 52000, 52400, 52800,
-       53200, 53700, 54200, 54600, 55000, 55400, 55800, 56200, 56600,
-       57000, 57400, 57800, 58200, 58700, 59200, 59600, 60000, 60400,
-       60800, 61200, 61600, 62000, 62400, 62800, 63300, 63800, 64200,
-       64600, 65000, 65400, 65800, 66200, 66600, 67000, 67400, 67800,
-       68200, 68700, 69200, 69600, 70000, 70400, 70800, 71200, 71600,
-       72000, 72400, 72800, 73200, 73600, 74100, 74600, 75000, 75400,
-       75800, 76200, 76600, 77000, 77400, 77800, 78200, 78600, 79000,
-       79400, 79800, 80300, 80800, 81200, 81600, 82000, 82400, 82800,
-       83200, 83600, 84000, 84400, 84800, 85200, 85600, 86000, 86400,
-       86800, 87300, 87800, 88200, 88600, 89000, 89400, 89800, 90200,
-       90600, 91000, 91400, 91800, 92200, 92600, 93000, 93400, 93800,
-       94200, 94600, 95000, 95500, 96000, 96400, 96800, 97200, 97600,
-       98000, 98400, 98800, 99200, 99600, 100000, 100400, 100800, 101200,
-       101600, 102000, 102400, 102800, 103200, 103600, 104000, 104400,
-       104800, 105200, 105600, 106100, 106600, 107000, 107400, 107800,
-       108200, 108600, 109000, 109400, 109800, 110200, 110600, 111000,
-       111400, 111800, 112200, 112600, 113000, 113400, 113800, 114200,
-       114600, 115000, 115400, 115800, 116200, 116600, 117000, 117400,
-       117800, 118200, 118600, 119000, 119400, 119800, 120200, 120600,
-       121000, 121400, 121800, 122200, 122600, 123000, 123400, 123800, 124200,
-       124600, 124900, 125000, 125000, 125000, 125000
-};
-
-/* OMAP4460 data */
-const struct ti_bandgap_data omap4460_data = {
-       .features = TI_BANDGAP_FEATURE_TSHUT |
-                       TI_BANDGAP_FEATURE_TSHUT_CONFIG |
-                       TI_BANDGAP_FEATURE_TALERT |
-                       TI_BANDGAP_FEATURE_MODE_CONFIG |
-                       TI_BANDGAP_FEATURE_POWER_SWITCH |
-                       TI_BANDGAP_FEATURE_CLK_CTRL |
-                       TI_BANDGAP_FEATURE_COUNTER,
-       .fclock_name = "bandgap_ts_fclk",
-       .div_ck_name = "div_ts_ck",
-       .conv_table = omap4460_adc_to_temp,
-       .adc_start_val = OMAP4460_ADC_START_VALUE,
-       .adc_end_val = OMAP4460_ADC_END_VALUE,
-       .expose_sensor = ti_thermal_expose_sensor,
-       .remove_sensor = ti_thermal_remove_sensor,
-       .report_temperature = ti_thermal_report_sensor_temperature,
-       .sensors = {
-               {
-               .registers = &omap4460_mpu_temp_sensor_registers,
-               .ts_data = &omap4460_mpu_temp_sensor_data,
-               .domain = "cpu",
-               .slope = OMAP_GRADIENT_SLOPE_4460,
-               .constant = OMAP_GRADIENT_CONST_4460,
-               .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4460,
-               .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4460,
-               .register_cooling = ti_thermal_register_cpu_cooling,
-               .unregister_cooling = ti_thermal_unregister_cpu_cooling,
-               },
-       },
-       .sensor_count = 1,
-};
-
-/* OMAP4470 data */
-const struct ti_bandgap_data omap4470_data = {
-       .features = TI_BANDGAP_FEATURE_TSHUT |
-                       TI_BANDGAP_FEATURE_TSHUT_CONFIG |
-                       TI_BANDGAP_FEATURE_TALERT |
-                       TI_BANDGAP_FEATURE_MODE_CONFIG |
-                       TI_BANDGAP_FEATURE_POWER_SWITCH |
-                       TI_BANDGAP_FEATURE_CLK_CTRL |
-                       TI_BANDGAP_FEATURE_COUNTER,
-       .fclock_name = "bandgap_ts_fclk",
-       .div_ck_name = "div_ts_ck",
-       .conv_table = omap4460_adc_to_temp,
-       .adc_start_val = OMAP4460_ADC_START_VALUE,
-       .adc_end_val = OMAP4460_ADC_END_VALUE,
-       .expose_sensor = ti_thermal_expose_sensor,
-       .remove_sensor = ti_thermal_remove_sensor,
-       .report_temperature = ti_thermal_report_sensor_temperature,
-       .sensors = {
-               {
-               .registers = &omap4460_mpu_temp_sensor_registers,
-               .ts_data = &omap4460_mpu_temp_sensor_data,
-               .domain = "cpu",
-               .slope = OMAP_GRADIENT_SLOPE_4470,
-               .constant = OMAP_GRADIENT_CONST_4470,
-               .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4470,
-               .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4470,
-               .register_cooling = ti_thermal_register_cpu_cooling,
-               .unregister_cooling = ti_thermal_unregister_cpu_cooling,
-               },
-       },
-       .sensor_count = 1,
-};
diff --git a/drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h b/drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h
deleted file mode 100644 (file)
index 6f2de3a..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * OMAP4xxx bandgap registers, bitfields and temperature definitions
- *
- * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
- * Contact:
- *   Eduardo Valentin <eduardo.valentin@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-#ifndef __OMAP4XXX_BANDGAP_H
-#define __OMAP4XXX_BANDGAP_H
-
-/**
- * *** OMAP4430 ***
- *
- * Below, in sequence, are the Register definitions,
- * the bitfields and the temperature definitions for OMAP4430.
- */
-
-/**
- * OMAP4430 register definitions
- *
- * Registers are defined as offsets. The offsets are
- * relative to FUSE_OPP_BGAP on 4430.
- */
-
-/* OMAP4430.FUSE_OPP_BGAP */
-#define OMAP4430_FUSE_OPP_BGAP                         0x0
-
-/* OMAP4430.TEMP_SENSOR  */
-#define OMAP4430_TEMP_SENSOR_CTRL_OFFSET               0xCC
-
-/**
- * Register and bit definitions for OMAP4430
- *
- * All the macros bellow define the required bits for
- * controlling temperature on OMAP4430. Bit defines are
- * grouped by register.
- */
-
-/* OMAP4430.TEMP_SENSOR bits */
-#define OMAP4430_BGAP_TEMPSOFF_MASK                    BIT(12)
-#define OMAP4430_BGAP_TSHUT_MASK                       BIT(11)
-#define OMAP4430_SINGLE_MODE_MASK                      BIT(10)
-#define OMAP4430_BGAP_TEMP_SENSOR_SOC_MASK             BIT(9)
-#define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_MASK            BIT(8)
-#define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK           (0xff << 0)
-
-/**
- * Temperature limits and thresholds for OMAP4430
- *
- * All the macros bellow are definitions for handling the
- * ADC conversions and representation of temperature limits
- * and thresholds for OMAP4430.
- */
-
-/* ADC conversion table limits */
-#define OMAP4430_ADC_START_VALUE                       0
-#define OMAP4430_ADC_END_VALUE                         127
-/* bandgap clock limits (no control on 4430) */
-#define OMAP4430_MAX_FREQ                              32768
-#define OMAP4430_MIN_FREQ                              32768
-/* sensor limits */
-#define OMAP4430_MIN_TEMP                              -40000
-#define OMAP4430_MAX_TEMP                              125000
-#define OMAP4430_HYST_VAL                              5000
-
-/**
- * *** OMAP4460 *** Applicable for OMAP4470
- *
- * Below, in sequence, are the Register definitions,
- * the bitfields and the temperature definitions for OMAP4460.
- */
-
-/**
- * OMAP4460 register definitions
- *
- * Registers are defined as offsets. The offsets are
- * relative to FUSE_OPP_BGAP on 4460.
- */
-
-/* OMAP4460.FUSE_OPP_BGAP */
-#define OMAP4460_FUSE_OPP_BGAP                         0x0
-
-/* OMAP4460.TEMP_SENSOR */
-#define OMAP4460_TEMP_SENSOR_CTRL_OFFSET               0xCC
-
-/* OMAP4460.BANDGAP_CTRL */
-#define OMAP4460_BGAP_CTRL_OFFSET                      0x118
-
-/* OMAP4460.BANDGAP_COUNTER */
-#define OMAP4460_BGAP_COUNTER_OFFSET                   0x11C
-
-/* OMAP4460.BANDGAP_THRESHOLD */
-#define OMAP4460_BGAP_THRESHOLD_OFFSET                 0x120
-
-/* OMAP4460.TSHUT_THRESHOLD */
-#define OMAP4460_BGAP_TSHUT_OFFSET                     0x124
-
-/* OMAP4460.BANDGAP_STATUS */
-#define OMAP4460_BGAP_STATUS_OFFSET                    0x128
-
-/**
- * Register bitfields for OMAP4460
- *
- * All the macros bellow define the required bits for
- * controlling temperature on OMAP4460. Bit defines are
- * grouped by register.
- */
-/* OMAP4460.TEMP_SENSOR bits */
-#define OMAP4460_BGAP_TEMPSOFF_MASK                    BIT(13)
-#define OMAP4460_BGAP_TEMP_SENSOR_SOC_MASK             BIT(11)
-#define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_MASK            BIT(10)
-#define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_MASK           (0x3ff << 0)
-
-/* OMAP4460.BANDGAP_CTRL bits */
-#define OMAP4460_SINGLE_MODE_MASK                      BIT(31)
-#define OMAP4460_MASK_HOT_MASK                         BIT(1)
-#define OMAP4460_MASK_COLD_MASK                                BIT(0)
-
-/* OMAP4460.BANDGAP_COUNTER bits */
-#define OMAP4460_COUNTER_MASK                          (0xffffff << 0)
-
-/* OMAP4460.BANDGAP_THRESHOLD bits */
-#define OMAP4460_T_HOT_MASK                            (0x3ff << 16)
-#define OMAP4460_T_COLD_MASK                           (0x3ff << 0)
-
-/* OMAP4460.TSHUT_THRESHOLD bits */
-#define OMAP4460_TSHUT_HOT_MASK                                (0x3ff << 16)
-#define OMAP4460_TSHUT_COLD_MASK                       (0x3ff << 0)
-
-/* OMAP4460.BANDGAP_STATUS bits */
-#define OMAP4460_CLEAN_STOP_MASK                       BIT(3)
-#define OMAP4460_BGAP_ALERT_MASK                       BIT(2)
-#define OMAP4460_HOT_FLAG_MASK                         BIT(1)
-#define OMAP4460_COLD_FLAG_MASK                                BIT(0)
-
-/**
- * Temperature limits and thresholds for OMAP4460
- *
- * All the macros bellow are definitions for handling the
- * ADC conversions and representation of temperature limits
- * and thresholds for OMAP4460.
- */
-
-/* ADC conversion table limits */
-#define OMAP4460_ADC_START_VALUE                       530
-#define OMAP4460_ADC_END_VALUE                         932
-/* bandgap clock limits */
-#define OMAP4460_MAX_FREQ                              1500000
-#define OMAP4460_MIN_FREQ                              1000000
-/* sensor limits */
-#define OMAP4460_MIN_TEMP                              -40000
-#define OMAP4460_MAX_TEMP                              123000
-#define OMAP4460_HYST_VAL                              5000
-/* interrupts thresholds */
-#define OMAP4460_TSHUT_HOT                             900     /* 122 deg C */
-#define OMAP4460_TSHUT_COLD                            895     /* 100 deg C */
-#define OMAP4460_T_HOT                                 800     /* 73 deg C */
-#define OMAP4460_T_COLD                                        795     /* 71 deg C */
-
-#endif /* __OMAP4XXX_BANDGAP_H */
diff --git a/drivers/staging/ti-soc-thermal/omap5-thermal-data.c b/drivers/staging/ti-soc-thermal/omap5-thermal-data.c
deleted file mode 100644 (file)
index eff0c80..0000000
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * OMAP5 thermal driver.
- *
- * Copyright (C) 2011-2012 Texas Instruments Inc.
- * Contact:
- *     Eduardo Valentin <eduardo.valentin@ti.com>
- *
- * 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 "omap5xxx-bandgap.h"
-
-/*
- * OMAP5430 has three instances of thermal sensor for MPU, GPU & CORE,
- * need to describe the individual registers and bit fields.
- */
-
-/*
- * OMAP5430 MPU thermal sensor register offset and bit-fields
- */
-static struct temp_sensor_registers
-omap5430_mpu_temp_sensor_registers = {
-       .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_MPU_OFFSET,
-       .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
-       .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
-       .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
-
-       .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
-       .mask_hot_mask = OMAP5430_MASK_HOT_MPU_MASK,
-       .mask_cold_mask = OMAP5430_MASK_COLD_MPU_MASK,
-       .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK,
-       .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK,
-       .mask_freeze_mask = OMAP5430_MASK_FREEZE_MPU_MASK,
-       .mask_clear_mask = OMAP5430_MASK_CLEAR_MPU_MASK,
-       .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_MPU_MASK,
-
-
-       .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET,
-       .counter_mask = OMAP5430_COUNTER_MASK,
-
-       .bgap_threshold = OMAP5430_BGAP_THRESHOLD_MPU_OFFSET,
-       .threshold_thot_mask = OMAP5430_T_HOT_MASK,
-       .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
-
-       .tshut_threshold = OMAP5430_BGAP_TSHUT_MPU_OFFSET,
-       .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
-       .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
-
-       .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
-       .status_clean_stop_mask = 0x0,
-       .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
-       .status_hot_mask = OMAP5430_HOT_MPU_FLAG_MASK,
-       .status_cold_mask = OMAP5430_COLD_MPU_FLAG_MASK,
-
-       .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_MPU_OFFSET,
-       .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_MPU_0_OFFSET,
-       .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_MPU_1_OFFSET,
-       .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_MPU_2_OFFSET,
-       .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_MPU_3_OFFSET,
-       .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_MPU_4_OFFSET,
-       .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_MPU,
-};
-
-/*
- * OMAP5430 GPU thermal sensor register offset and bit-fields
- */
-static struct temp_sensor_registers
-omap5430_gpu_temp_sensor_registers = {
-       .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_GPU_OFFSET,
-       .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
-       .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
-       .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
-
-       .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
-       .mask_hot_mask = OMAP5430_MASK_HOT_GPU_MASK,
-       .mask_cold_mask = OMAP5430_MASK_COLD_GPU_MASK,
-       .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK,
-       .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK,
-       .mask_freeze_mask = OMAP5430_MASK_FREEZE_GPU_MASK,
-       .mask_clear_mask = OMAP5430_MASK_CLEAR_GPU_MASK,
-       .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_GPU_MASK,
-
-       .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET,
-       .counter_mask = OMAP5430_COUNTER_MASK,
-
-       .bgap_threshold = OMAP5430_BGAP_THRESHOLD_GPU_OFFSET,
-       .threshold_thot_mask = OMAP5430_T_HOT_MASK,
-       .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
-
-       .tshut_threshold = OMAP5430_BGAP_TSHUT_GPU_OFFSET,
-       .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
-       .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
-
-       .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
-       .status_clean_stop_mask = 0x0,
-       .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
-       .status_hot_mask = OMAP5430_HOT_GPU_FLAG_MASK,
-       .status_cold_mask = OMAP5430_COLD_GPU_FLAG_MASK,
-
-       .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_GPU_OFFSET,
-       .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_GPU_0_OFFSET,
-       .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_GPU_1_OFFSET,
-       .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_GPU_2_OFFSET,
-       .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_GPU_3_OFFSET,
-       .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_GPU_4_OFFSET,
-
-       .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_GPU,
-};
-
-/*
- * OMAP5430 CORE thermal sensor register offset and bit-fields
- */
-static struct temp_sensor_registers
-omap5430_core_temp_sensor_registers = {
-       .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_CORE_OFFSET,
-       .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
-       .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
-       .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
-
-       .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
-       .mask_hot_mask = OMAP5430_MASK_HOT_CORE_MASK,
-       .mask_cold_mask = OMAP5430_MASK_COLD_CORE_MASK,
-       .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK,
-       .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK,
-       .mask_freeze_mask = OMAP5430_MASK_FREEZE_CORE_MASK,
-       .mask_clear_mask = OMAP5430_MASK_CLEAR_CORE_MASK,
-       .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_CORE_MASK,
-
-       .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET,
-       .counter_mask = OMAP5430_COUNTER_MASK,
-
-       .bgap_threshold = OMAP5430_BGAP_THRESHOLD_CORE_OFFSET,
-       .threshold_thot_mask = OMAP5430_T_HOT_MASK,
-       .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
-
-       .tshut_threshold = OMAP5430_BGAP_TSHUT_CORE_OFFSET,
-       .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
-       .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
-
-       .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
-       .status_clean_stop_mask = 0x0,
-       .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
-       .status_hot_mask = OMAP5430_HOT_CORE_FLAG_MASK,
-       .status_cold_mask = OMAP5430_COLD_CORE_FLAG_MASK,
-
-       .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_CORE_OFFSET,
-       .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_CORE_0_OFFSET,
-       .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_CORE_1_OFFSET,
-       .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_CORE_2_OFFSET,
-       .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_CORE_3_OFFSET,
-       .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_CORE_4_OFFSET,
-
-       .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_CORE,
-};
-
-/* Thresholds and limits for OMAP5430 MPU temperature sensor */
-static struct temp_sensor_data omap5430_mpu_temp_sensor_data = {
-       .tshut_hot = OMAP5430_MPU_TSHUT_HOT,
-       .tshut_cold = OMAP5430_MPU_TSHUT_COLD,
-       .t_hot = OMAP5430_MPU_T_HOT,
-       .t_cold = OMAP5430_MPU_T_COLD,
-       .min_freq = OMAP5430_MPU_MIN_FREQ,
-       .max_freq = OMAP5430_MPU_MAX_FREQ,
-       .max_temp = OMAP5430_MPU_MAX_TEMP,
-       .min_temp = OMAP5430_MPU_MIN_TEMP,
-       .hyst_val = OMAP5430_MPU_HYST_VAL,
-       .update_int1 = 1000,
-       .update_int2 = 2000,
-};
-
-/* Thresholds and limits for OMAP5430 GPU temperature sensor */
-static struct temp_sensor_data omap5430_gpu_temp_sensor_data = {
-       .tshut_hot = OMAP5430_GPU_TSHUT_HOT,
-       .tshut_cold = OMAP5430_GPU_TSHUT_COLD,
-       .t_hot = OMAP5430_GPU_T_HOT,
-       .t_cold = OMAP5430_GPU_T_COLD,
-       .min_freq = OMAP5430_GPU_MIN_FREQ,
-       .max_freq = OMAP5430_GPU_MAX_FREQ,
-       .max_temp = OMAP5430_GPU_MAX_TEMP,
-       .min_temp = OMAP5430_GPU_MIN_TEMP,
-       .hyst_val = OMAP5430_GPU_HYST_VAL,
-       .update_int1 = 1000,
-       .update_int2 = 2000,
-};
-
-/* Thresholds and limits for OMAP5430 CORE temperature sensor */
-static struct temp_sensor_data omap5430_core_temp_sensor_data = {
-       .tshut_hot = OMAP5430_CORE_TSHUT_HOT,
-       .tshut_cold = OMAP5430_CORE_TSHUT_COLD,
-       .t_hot = OMAP5430_CORE_T_HOT,
-       .t_cold = OMAP5430_CORE_T_COLD,
-       .min_freq = OMAP5430_CORE_MIN_FREQ,
-       .max_freq = OMAP5430_CORE_MAX_FREQ,
-       .max_temp = OMAP5430_CORE_MAX_TEMP,
-       .min_temp = OMAP5430_CORE_MIN_TEMP,
-       .hyst_val = OMAP5430_CORE_HYST_VAL,
-       .update_int1 = 1000,
-       .update_int2 = 2000,
-};
-
-/*
- * OMAP54xx ES2.0 : Temperature values in milli degree celsius
- * ADC code values from 540 to 945
- */
-static int
-omap5430_adc_to_temp[
-       OMAP5430_ADC_END_VALUE - OMAP5430_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, -21600, -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, 21100,
-       /* 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, 122400, 122600, 123000,
-       123400,
-       /* Index 940 - 945 */
-       123800, 1242000, 124600, 124900, 125000, 125000,
-};
-
-/* OMAP54xx ES2.0 data */
-const struct ti_bandgap_data omap5430_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 = omap5430_adc_to_temp,
-       .adc_start_val = OMAP5430_ADC_START_VALUE,
-       .adc_end_val = OMAP5430_ADC_END_VALUE,
-       .expose_sensor = ti_thermal_expose_sensor,
-       .remove_sensor = ti_thermal_remove_sensor,
-       .report_temperature = ti_thermal_report_sensor_temperature,
-       .sensors = {
-               {
-               .registers = &omap5430_mpu_temp_sensor_registers,
-               .ts_data = &omap5430_mpu_temp_sensor_data,
-               .domain = "cpu",
-               .register_cooling = ti_thermal_register_cpu_cooling,
-               .unregister_cooling = ti_thermal_unregister_cpu_cooling,
-               .slope = OMAP_GRADIENT_SLOPE_5430_CPU,
-               .constant = OMAP_GRADIENT_CONST_5430_CPU,
-               .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU,
-               .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_CPU,
-               },
-               {
-               .registers = &omap5430_gpu_temp_sensor_registers,
-               .ts_data = &omap5430_gpu_temp_sensor_data,
-               .domain = "gpu",
-               .slope = OMAP_GRADIENT_SLOPE_5430_GPU,
-               .constant = OMAP_GRADIENT_CONST_5430_GPU,
-               .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU,
-               .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_GPU,
-               },
-               {
-               .registers = &omap5430_core_temp_sensor_registers,
-               .ts_data = &omap5430_core_temp_sensor_data,
-               .domain = "core",
-               },
-       },
-       .sensor_count = 3,
-};
diff --git a/drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h b/drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h
deleted file mode 100644 (file)
index 400b55d..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * OMAP5xxx bandgap registers, bitfields and temperature definitions
- *
- * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
- * Contact:
- *   Eduardo Valentin <eduardo.valentin@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-#ifndef __OMAP5XXX_BANDGAP_H
-#define __OMAP5XXX_BANDGAP_H
-
-/**
- * *** OMAP5430 ***
- *
- * Below, in sequence, are the Register definitions,
- * the bitfields and the temperature definitions for OMAP5430.
- */
-
-/**
- * OMAP5430 register definitions
- *
- * Registers are defined as offsets. The offsets are
- * relative to FUSE_OPP_BGAP_GPU on 5430.
- *
- * Register below are grouped by domain (not necessarily in offset order)
- */
-
-/* OMAP5430.GPU register offsets */
-#define OMAP5430_FUSE_OPP_BGAP_GPU                     0x0
-#define OMAP5430_TEMP_SENSOR_GPU_OFFSET                        0x150
-#define OMAP5430_BGAP_THRESHOLD_GPU_OFFSET             0x1A8
-#define OMAP5430_BGAP_TSHUT_GPU_OFFSET                 0x1B4
-#define OMAP5430_BGAP_CUMUL_DTEMP_GPU_OFFSET           0x1C0
-#define OMAP5430_BGAP_DTEMP_GPU_0_OFFSET               0x1F4
-#define OMAP5430_BGAP_DTEMP_GPU_1_OFFSET               0x1F8
-#define OMAP5430_BGAP_DTEMP_GPU_2_OFFSET               0x1FC
-#define OMAP5430_BGAP_DTEMP_GPU_3_OFFSET               0x200
-#define OMAP5430_BGAP_DTEMP_GPU_4_OFFSET               0x204
-
-/* OMAP5430.MPU register offsets */
-#define OMAP5430_FUSE_OPP_BGAP_MPU                     0x4
-#define OMAP5430_TEMP_SENSOR_MPU_OFFSET                        0x14C
-#define OMAP5430_BGAP_THRESHOLD_MPU_OFFSET             0x1A4
-#define OMAP5430_BGAP_TSHUT_MPU_OFFSET                 0x1B0
-#define OMAP5430_BGAP_CUMUL_DTEMP_MPU_OFFSET           0x1BC
-#define OMAP5430_BGAP_DTEMP_MPU_0_OFFSET               0x1E0
-#define OMAP5430_BGAP_DTEMP_MPU_1_OFFSET               0x1E4
-#define OMAP5430_BGAP_DTEMP_MPU_2_OFFSET               0x1E8
-#define OMAP5430_BGAP_DTEMP_MPU_3_OFFSET               0x1EC
-#define OMAP5430_BGAP_DTEMP_MPU_4_OFFSET               0x1F0
-
-/* OMAP5430.MPU register offsets */
-#define OMAP5430_FUSE_OPP_BGAP_CORE                    0x8
-#define OMAP5430_TEMP_SENSOR_CORE_OFFSET               0x154
-#define OMAP5430_BGAP_THRESHOLD_CORE_OFFSET            0x1AC
-#define OMAP5430_BGAP_TSHUT_CORE_OFFSET                        0x1B8
-#define OMAP5430_BGAP_CUMUL_DTEMP_CORE_OFFSET          0x1C4
-#define OMAP5430_BGAP_DTEMP_CORE_0_OFFSET              0x208
-#define OMAP5430_BGAP_DTEMP_CORE_1_OFFSET              0x20C
-#define OMAP5430_BGAP_DTEMP_CORE_2_OFFSET              0x210
-#define OMAP5430_BGAP_DTEMP_CORE_3_OFFSET              0x214
-#define OMAP5430_BGAP_DTEMP_CORE_4_OFFSET              0x218
-
-/* OMAP5430.common register offsets */
-#define OMAP5430_BGAP_CTRL_OFFSET                      0x1A0
-#define OMAP5430_BGAP_STATUS_OFFSET                    0x1C8
-
-/**
- * Register bitfields for OMAP5430
- *
- * All the macros bellow define the required bits for
- * controlling temperature on OMAP5430. Bit defines are
- * grouped by register.
- */
-
-/* OMAP5430.TEMP_SENSOR */
-#define OMAP5430_BGAP_TEMP_SENSOR_SOC_MASK             BIT(12)
-#define OMAP5430_BGAP_TEMPSOFF_MASK                    BIT(11)
-#define OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK            BIT(10)
-#define OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK           (0x3ff << 0)
-
-/* OMAP5430.BANDGAP_CTRL */
-#define OMAP5430_MASK_SIDLEMODE_MASK                   (0x3 << 30)
-#define OMAP5430_MASK_COUNTER_DELAY_MASK               (0x7 << 27)
-#define OMAP5430_MASK_FREEZE_CORE_MASK                 BIT(23)
-#define OMAP5430_MASK_FREEZE_GPU_MASK                  BIT(22)
-#define OMAP5430_MASK_FREEZE_MPU_MASK                  BIT(21)
-#define OMAP5430_MASK_CLEAR_CORE_MASK                  BIT(20)
-#define OMAP5430_MASK_CLEAR_GPU_MASK                   BIT(19)
-#define OMAP5430_MASK_CLEAR_MPU_MASK                   BIT(18)
-#define OMAP5430_MASK_CLEAR_ACCUM_CORE_MASK            BIT(17)
-#define OMAP5430_MASK_CLEAR_ACCUM_GPU_MASK             BIT(16)
-#define OMAP5430_MASK_CLEAR_ACCUM_MPU_MASK             BIT(15)
-#define OMAP5430_MASK_HOT_CORE_MASK                    BIT(5)
-#define OMAP5430_MASK_COLD_CORE_MASK                   BIT(4)
-#define OMAP5430_MASK_HOT_GPU_MASK                     BIT(3)
-#define OMAP5430_MASK_COLD_GPU_MASK                    BIT(2)
-#define OMAP5430_MASK_HOT_MPU_MASK                     BIT(1)
-#define OMAP5430_MASK_COLD_MPU_MASK                    BIT(0)
-
-/* OMAP5430.BANDGAP_COUNTER */
-#define OMAP5430_COUNTER_MASK                          (0xffffff << 0)
-
-/* OMAP5430.BANDGAP_THRESHOLD */
-#define OMAP5430_T_HOT_MASK                            (0x3ff << 16)
-#define OMAP5430_T_COLD_MASK                           (0x3ff << 0)
-
-/* OMAP5430.TSHUT_THRESHOLD */
-#define OMAP5430_TSHUT_HOT_MASK                                (0x3ff << 16)
-#define OMAP5430_TSHUT_COLD_MASK                       (0x3ff << 0)
-
-/* OMAP5430.BANDGAP_CUMUL_DTEMP_MPU */
-#define OMAP5430_CUMUL_DTEMP_MPU_MASK                  (0xffffffff << 0)
-
-/* OMAP5430.BANDGAP_CUMUL_DTEMP_GPU */
-#define OMAP5430_CUMUL_DTEMP_GPU_MASK                  (0xffffffff << 0)
-
-/* OMAP5430.BANDGAP_CUMUL_DTEMP_CORE */
-#define OMAP5430_CUMUL_DTEMP_CORE_MASK                 (0xffffffff << 0)
-
-/* OMAP5430.BANDGAP_STATUS */
-#define OMAP5430_BGAP_ALERT_MASK                       BIT(31)
-#define OMAP5430_HOT_CORE_FLAG_MASK                    BIT(5)
-#define OMAP5430_COLD_CORE_FLAG_MASK                   BIT(4)
-#define OMAP5430_HOT_GPU_FLAG_MASK                     BIT(3)
-#define OMAP5430_COLD_GPU_FLAG_MASK                    BIT(2)
-#define OMAP5430_HOT_MPU_FLAG_MASK                     BIT(1)
-#define OMAP5430_COLD_MPU_FLAG_MASK                    BIT(0)
-
-/**
- * Temperature limits and thresholds for OMAP5430
- *
- * All the macros bellow are definitions for handling the
- * ADC conversions and representation of temperature limits
- * and thresholds for OMAP5430. Definitions are grouped
- * by temperature domain.
- */
-
-/* OMAP5430.common temperature definitions */
-/* ADC conversion table limits */
-#define OMAP5430_ADC_START_VALUE                       540
-#define OMAP5430_ADC_END_VALUE                         945
-
-/* OMAP5430.GPU temperature definitions */
-/* bandgap clock limits */
-#define OMAP5430_GPU_MAX_FREQ                          1500000
-#define OMAP5430_GPU_MIN_FREQ                          1000000
-/* sensor limits */
-#define OMAP5430_GPU_MIN_TEMP                          -40000
-#define OMAP5430_GPU_MAX_TEMP                          125000
-#define OMAP5430_GPU_HYST_VAL                          5000
-/* interrupts thresholds */
-#define OMAP5430_GPU_TSHUT_HOT                         915
-#define OMAP5430_GPU_TSHUT_COLD                                900
-#define OMAP5430_GPU_T_HOT                             800
-#define OMAP5430_GPU_T_COLD                            795
-
-/* OMAP5430.MPU temperature definitions */
-/* bandgap clock limits */
-#define OMAP5430_MPU_MAX_FREQ                          1500000
-#define OMAP5430_MPU_MIN_FREQ                          1000000
-/* sensor limits */
-#define OMAP5430_MPU_MIN_TEMP                          -40000
-#define OMAP5430_MPU_MAX_TEMP                          125000
-#define OMAP5430_MPU_HYST_VAL                          5000
-/* interrupts thresholds */
-#define OMAP5430_MPU_TSHUT_HOT                         915
-#define OMAP5430_MPU_TSHUT_COLD                                900
-#define OMAP5430_MPU_T_HOT                             800
-#define OMAP5430_MPU_T_COLD                            795
-
-/* OMAP5430.CORE temperature definitions */
-/* bandgap clock limits */
-#define OMAP5430_CORE_MAX_FREQ                         1500000
-#define OMAP5430_CORE_MIN_FREQ                         1000000
-/* sensor limits */
-#define OMAP5430_CORE_MIN_TEMP                         -40000
-#define OMAP5430_CORE_MAX_TEMP                         125000
-#define OMAP5430_CORE_HYST_VAL                         5000
-/* interrupts thresholds */
-#define OMAP5430_CORE_TSHUT_HOT                                915
-#define OMAP5430_CORE_TSHUT_COLD                       900
-#define OMAP5430_CORE_T_HOT                            800
-#define OMAP5430_CORE_T_COLD                           795
-
-#endif /* __OMAP5XXX_BANDGAP_H */
diff --git a/drivers/staging/ti-soc-thermal/ti-bandgap.c b/drivers/staging/ti-soc-thermal/ti-bandgap.c
deleted file mode 100644 (file)
index f20c1cf..0000000
+++ /dev/null
@@ -1,1546 +0,0 @@
-/*
- * TI Bandgap temperature sensor driver
- *
- * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
- * Author: J Keerthy <j-keerthy@ti.com>
- * Author: Moiz Sonasath <m-sonasath@ti.com>
- * Couple of fixes, DT and MFD adaptation:
- *   Eduardo Valentin <eduardo.valentin@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/export.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/clk.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/reboot.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-#include <linux/of_irq.h>
-#include <linux/io.h>
-
-#include "ti-bandgap.h"
-
-/***   Helper functions to access registers and their bitfields   ***/
-
-/**
- * ti_bandgap_readl() - simple read helper function
- * @bgp: pointer to ti_bandgap structure
- * @reg: desired register (offset) to be read
- *
- * Helper function to read bandgap registers. It uses the io remapped area.
- * Return: the register value.
- */
-static u32 ti_bandgap_readl(struct ti_bandgap *bgp, u32 reg)
-{
-       return readl(bgp->base + reg);
-}
-
-/**
- * ti_bandgap_writel() - simple write helper function
- * @bgp: pointer to ti_bandgap structure
- * @val: desired register value to be written
- * @reg: desired register (offset) to be written
- *
- * Helper function to write bandgap registers. It uses the io remapped area.
- */
-static void ti_bandgap_writel(struct ti_bandgap *bgp, u32 val, u32 reg)
-{
-       writel(val, bgp->base + reg);
-}
-
-/**
- * DOC: macro to update bits.
- *
- * RMW_BITS() - used to read, modify and update bandgap bitfields.
- *            The value passed will be shifted.
- */
-#define RMW_BITS(bgp, id, reg, mask, val)                      \
-do {                                                           \
-       struct temp_sensor_registers *t;                        \
-       u32 r;                                                  \
-                                                               \
-       t = bgp->conf->sensors[(id)].registers;         \
-       r = ti_bandgap_readl(bgp, t->reg);                      \
-       r &= ~t->mask;                                          \
-       r |= (val) << __ffs(t->mask);                           \
-       ti_bandgap_writel(bgp, r, t->reg);                      \
-} while (0)
-
-/***   Basic helper functions   ***/
-
-/**
- * ti_bandgap_power() - controls the power state of a bandgap device
- * @bgp: pointer to ti_bandgap structure
- * @on: desired power state (1 - on, 0 - off)
- *
- * Used to power on/off a bandgap device instance. Only used on those
- * that features tempsoff bit.
- *
- * Return: 0 on success, -ENOTSUPP if tempsoff is not supported.
- */
-static int ti_bandgap_power(struct ti_bandgap *bgp, bool on)
-{
-       int i, ret = 0;
-
-       if (!TI_BANDGAP_HAS(bgp, POWER_SWITCH)) {
-               ret = -ENOTSUPP;
-               goto exit;
-       }
-
-       for (i = 0; i < bgp->conf->sensor_count; i++)
-               /* active on 0 */
-               RMW_BITS(bgp, i, temp_sensor_ctrl, bgap_tempsoff_mask, !on);
-
-exit:
-       return ret;
-}
-
-/**
- * ti_bandgap_read_temp() - helper function to read sensor temperature
- * @bgp: pointer to ti_bandgap structure
- * @id: bandgap sensor id
- *
- * Function to concentrate the steps to read sensor temperature register.
- * This function is desired because, depending on bandgap device version,
- * it might be needed to freeze the bandgap state machine, before fetching
- * the register value.
- *
- * Return: temperature in ADC values.
- */
-static u32 ti_bandgap_read_temp(struct ti_bandgap *bgp, int id)
-{
-       struct temp_sensor_registers *tsr;
-       u32 temp, reg;
-
-       tsr = bgp->conf->sensors[id].registers;
-       reg = tsr->temp_sensor_ctrl;
-
-       if (TI_BANDGAP_HAS(bgp, FREEZE_BIT)) {
-               RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1);
-               /*
-                * In case we cannot read from cur_dtemp / dtemp_0,
-                * then we read from the last valid temp read
-                */
-               reg = tsr->ctrl_dtemp_1;
-       }
-
-       /* read temperature */
-       temp = ti_bandgap_readl(bgp, reg);
-       temp &= tsr->bgap_dtemp_mask;
-
-       if (TI_BANDGAP_HAS(bgp, FREEZE_BIT))
-               RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 0);
-
-       return temp;
-}
-
-/***   IRQ handlers   ***/
-
-/**
- * ti_bandgap_talert_irq_handler() - handles Temperature alert IRQs
- * @irq: IRQ number
- * @data: private data (struct ti_bandgap *)
- *
- * This is the Talert handler. Use it only if bandgap device features
- * HAS(TALERT). This handler goes over all sensors and checks their
- * conditions and acts accordingly. In case there are events pending,
- * it will reset the event mask to wait for the opposite event (next event).
- * Every time there is a new event, it will be reported to thermal layer.
- *
- * Return: IRQ_HANDLED
- */
-static irqreturn_t ti_bandgap_talert_irq_handler(int irq, void *data)
-{
-       struct ti_bandgap *bgp = data;
-       struct temp_sensor_registers *tsr;
-       u32 t_hot = 0, t_cold = 0, ctrl;
-       int i;
-
-       spin_lock(&bgp->lock);
-       for (i = 0; i < bgp->conf->sensor_count; i++) {
-               tsr = bgp->conf->sensors[i].registers;
-               ctrl = ti_bandgap_readl(bgp, tsr->bgap_status);
-
-               /* Read the status of t_hot */
-               t_hot = ctrl & tsr->status_hot_mask;
-
-               /* Read the status of t_cold */
-               t_cold = ctrl & tsr->status_cold_mask;
-
-               if (!t_cold && !t_hot)
-                       continue;
-
-               ctrl = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
-               /*
-                * One TALERT interrupt: Two sources
-                * If the interrupt is due to t_hot then mask t_hot and
-                * and unmask t_cold else mask t_cold and unmask t_hot
-                */
-               if (t_hot) {
-                       ctrl &= ~tsr->mask_hot_mask;
-                       ctrl |= tsr->mask_cold_mask;
-               } else if (t_cold) {
-                       ctrl &= ~tsr->mask_cold_mask;
-                       ctrl |= tsr->mask_hot_mask;
-               }
-
-               ti_bandgap_writel(bgp, ctrl, tsr->bgap_mask_ctrl);
-
-               dev_dbg(bgp->dev,
-                       "%s: IRQ from %s sensor: hotevent %d coldevent %d\n",
-                       __func__, bgp->conf->sensors[i].domain,
-                       t_hot, t_cold);
-
-               /* report temperature to whom may concern */
-               if (bgp->conf->report_temperature)
-                       bgp->conf->report_temperature(bgp, i);
-       }
-       spin_unlock(&bgp->lock);
-
-       return IRQ_HANDLED;
-}
-
-/**
- * ti_bandgap_tshut_irq_handler() - handles Temperature shutdown signal
- * @irq: IRQ number
- * @data: private data (unused)
- *
- * This is the Tshut handler. Use it only if bandgap device features
- * HAS(TSHUT). If any sensor fires the Tshut signal, we simply shutdown
- * the system.
- *
- * Return: IRQ_HANDLED
- */
-static irqreturn_t ti_bandgap_tshut_irq_handler(int irq, void *data)
-{
-       pr_emerg("%s: TSHUT temperature reached. Needs shut down...\n",
-                __func__);
-
-       orderly_poweroff(true);
-
-       return IRQ_HANDLED;
-}
-
-/***   Helper functions which manipulate conversion ADC <-> mi Celsius   ***/
-
-/**
- * ti_bandgap_adc_to_mcelsius() - converts an ADC value to mCelsius scale
- * @bgp: struct ti_bandgap pointer
- * @adc_val: value in ADC representation
- * @t: address where to write the resulting temperature in mCelsius
- *
- * Simple conversion from ADC representation to mCelsius. In case the ADC value
- * is out of the ADC conv table range, it returns -ERANGE, 0 on success.
- * The conversion table is indexed by the ADC values.
- *
- * Return: 0 if conversion was successful, else -ERANGE in case the @adc_val
- * argument is out of the ADC conv table range.
- */
-static
-int ti_bandgap_adc_to_mcelsius(struct ti_bandgap *bgp, int adc_val, int *t)
-{
-       const struct ti_bandgap_data *conf = bgp->conf;
-       int ret = 0;
-
-       /* look up for temperature in the table and return the temperature */
-       if (adc_val < conf->adc_start_val || adc_val > conf->adc_end_val) {
-               ret = -ERANGE;
-               goto exit;
-       }
-
-       *t = bgp->conf->conv_table[adc_val - conf->adc_start_val];
-
-exit:
-       return ret;
-}
-
-/**
- * ti_bandgap_mcelsius_to_adc() - converts a mCelsius value to ADC scale
- * @bgp: struct ti_bandgap pointer
- * @temp: value in mCelsius
- * @adc: address where to write the resulting temperature in ADC representation
- *
- * Simple conversion from mCelsius to ADC values. In case the temp value
- * is out of the ADC conv table range, it returns -ERANGE, 0 on success.
- * The conversion table is indexed by the ADC values.
- *
- * Return: 0 if conversion was successful, else -ERANGE in case the @temp
- * argument is out of the ADC conv table range.
- */
-static
-int ti_bandgap_mcelsius_to_adc(struct ti_bandgap *bgp, long temp, int *adc)
-{
-       const struct ti_bandgap_data *conf = bgp->conf;
-       const int *conv_table = bgp->conf->conv_table;
-       int high, low, mid, ret = 0;
-
-       low = 0;
-       high = conf->adc_end_val - conf->adc_start_val;
-       mid = (high + low) / 2;
-
-       if (temp < conv_table[low] || temp > conv_table[high]) {
-               ret = -ERANGE;
-               goto exit;
-       }
-
-       while (low < high) {
-               if (temp < conv_table[mid])
-                       high = mid - 1;
-               else
-                       low = mid + 1;
-               mid = (low + high) / 2;
-       }
-
-       *adc = conf->adc_start_val + low;
-
-exit:
-       return ret;
-}
-
-/**
- * ti_bandgap_add_hyst() - add hysteresis (in mCelsius) to an ADC value
- * @bgp: struct ti_bandgap pointer
- * @adc_val: temperature value in ADC representation
- * @hyst_val: hysteresis value in mCelsius
- * @sum: address where to write the resulting temperature (in ADC scale)
- *
- * Adds an hysteresis value (in mCelsius) to a ADC temperature value.
- *
- * Return: 0 on success, -ERANGE otherwise.
- */
-static
-int ti_bandgap_add_hyst(struct ti_bandgap *bgp, int adc_val, int hyst_val,
-                       u32 *sum)
-{
-       int temp, ret;
-
-       /*
-        * Need to add in the mcelsius domain, so we have a temperature
-        * the conv_table range
-        */
-       ret = ti_bandgap_adc_to_mcelsius(bgp, adc_val, &temp);
-       if (ret < 0)
-               goto exit;
-
-       temp += hyst_val;
-
-       ret = ti_bandgap_mcelsius_to_adc(bgp, temp, sum);
-
-exit:
-       return ret;
-}
-
-/***   Helper functions handling device Alert/Shutdown signals   ***/
-
-/**
- * ti_bandgap_unmask_interrupts() - unmasks the events of thot & tcold
- * @bgp: struct ti_bandgap pointer
- * @id: bandgap sensor id
- * @t_hot: hot temperature value to trigger alert signal
- * @t_cold: cold temperature value to trigger alert signal
- *
- * Checks the requested t_hot and t_cold values and configures the IRQ event
- * masks accordingly. Call this function only if bandgap features HAS(TALERT).
- */
-static void ti_bandgap_unmask_interrupts(struct ti_bandgap *bgp, int id,
-                                        u32 t_hot, u32 t_cold)
-{
-       struct temp_sensor_registers *tsr;
-       u32 temp, reg_val;
-
-       /* Read the current on die temperature */
-       temp = ti_bandgap_read_temp(bgp, id);
-
-       tsr = bgp->conf->sensors[id].registers;
-       reg_val = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
-
-       if (temp < t_hot)
-               reg_val |= tsr->mask_hot_mask;
-       else
-               reg_val &= ~tsr->mask_hot_mask;
-
-       if (t_cold < temp)
-               reg_val |= tsr->mask_cold_mask;
-       else
-               reg_val &= ~tsr->mask_cold_mask;
-       ti_bandgap_writel(bgp, reg_val, tsr->bgap_mask_ctrl);
-}
-
-/**
- * ti_bandgap_update_alert_threshold() - sequence to update thresholds
- * @bgp: struct ti_bandgap pointer
- * @id: bandgap sensor id
- * @val: value (ADC) of a new threshold
- * @hot: desired threshold to be updated. true if threshold hot, false if
- *       threshold cold
- *
- * It will program the required thresholds (hot and cold) for TALERT signal.
- * This function can be used to update t_hot or t_cold, depending on @hot value.
- * It checks the resulting t_hot and t_cold values, based on the new passed @val
- * and configures the thresholds so that t_hot is always greater than t_cold.
- * Call this function only if bandgap features HAS(TALERT).
- *
- * Return: 0 if no error, else corresponding error
- */
-static int ti_bandgap_update_alert_threshold(struct ti_bandgap *bgp, int id,
-                                            int val, bool hot)
-{
-       struct temp_sensor_data *ts_data = bgp->conf->sensors[id].ts_data;
-       struct temp_sensor_registers *tsr;
-       u32 thresh_val, reg_val, t_hot, t_cold;
-       int err = 0;
-
-       tsr = bgp->conf->sensors[id].registers;
-
-       /* obtain the current value */
-       thresh_val = ti_bandgap_readl(bgp, tsr->bgap_threshold);
-       t_cold = (thresh_val & tsr->threshold_tcold_mask) >>
-               __ffs(tsr->threshold_tcold_mask);
-       t_hot = (thresh_val & tsr->threshold_thot_mask) >>
-               __ffs(tsr->threshold_thot_mask);
-       if (hot)
-               t_hot = val;
-       else
-               t_cold = val;
-
-       if (t_cold > t_hot) {
-               if (hot)
-                       err = ti_bandgap_add_hyst(bgp, t_hot,
-                                                 -ts_data->hyst_val,
-                                                 &t_cold);
-               else
-                       err = ti_bandgap_add_hyst(bgp, t_cold,
-                                                 ts_data->hyst_val,
-                                                 &t_hot);
-       }
-
-       /* write the new threshold values */
-       reg_val = thresh_val &
-                 ~(tsr->threshold_thot_mask | tsr->threshold_tcold_mask);
-       reg_val |= (t_hot << __ffs(tsr->threshold_thot_mask)) |
-                  (t_cold << __ffs(tsr->threshold_tcold_mask));
-       ti_bandgap_writel(bgp, reg_val, tsr->bgap_threshold);
-
-       if (err) {
-               dev_err(bgp->dev, "failed to reprogram thot threshold\n");
-               err = -EIO;
-               goto exit;
-       }
-
-       ti_bandgap_unmask_interrupts(bgp, id, t_hot, t_cold);
-exit:
-       return err;
-}
-
-/**
- * ti_bandgap_validate() - helper to check the sanity of a struct ti_bandgap
- * @bgp: struct ti_bandgap pointer
- * @id: bandgap sensor id
- *
- * Checks if the bandgap pointer is valid and if the sensor id is also
- * applicable.
- *
- * Return: 0 if no errors, -EINVAL for invalid @bgp pointer or -ERANGE if
- * @id cannot index @bgp sensors.
- */
-static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id)
-{
-       int ret = 0;
-
-       if (IS_ERR_OR_NULL(bgp)) {
-               pr_err("%s: invalid bandgap pointer\n", __func__);
-               ret = -EINVAL;
-               goto exit;
-       }
-
-       if ((id < 0) || (id >= bgp->conf->sensor_count)) {
-               dev_err(bgp->dev, "%s: sensor id out of range (%d)\n",
-                       __func__, id);
-               ret = -ERANGE;
-       }
-
-exit:
-       return ret;
-}
-
-/**
- * _ti_bandgap_write_threshold() - helper to update TALERT t_cold or t_hot
- * @bgp: struct ti_bandgap pointer
- * @id: bandgap sensor id
- * @val: value (mCelsius) of a new threshold
- * @hot: desired threshold to be updated. true if threshold hot, false if
- *       threshold cold
- *
- * It will update the required thresholds (hot and cold) for TALERT signal.
- * This function can be used to update t_hot or t_cold, depending on @hot value.
- * Validates the mCelsius range and update the requested threshold.
- * Call this function only if bandgap features HAS(TALERT).
- *
- * Return: 0 if no error, else corresponding error value.
- */
-static int _ti_bandgap_write_threshold(struct ti_bandgap *bgp, int id, int val,
-                                      bool hot)
-{
-       struct temp_sensor_data *ts_data;
-       struct temp_sensor_registers *tsr;
-       u32 adc_val;
-       int ret;
-
-       ret = ti_bandgap_validate(bgp, id);
-       if (ret)
-               goto exit;
-
-       if (!TI_BANDGAP_HAS(bgp, TALERT)) {
-               ret = -ENOTSUPP;
-               goto exit;
-       }
-
-       ts_data = bgp->conf->sensors[id].ts_data;
-       tsr = bgp->conf->sensors[id].registers;
-       if (hot) {
-               if (val < ts_data->min_temp + ts_data->hyst_val)
-                       ret = -EINVAL;
-       } else {
-               if (val > ts_data->max_temp + ts_data->hyst_val)
-                       ret = -EINVAL;
-       }
-
-       if (ret)
-               goto exit;
-
-       ret = ti_bandgap_mcelsius_to_adc(bgp, val, &adc_val);
-       if (ret < 0)
-               goto exit;
-
-       spin_lock(&bgp->lock);
-       ret = ti_bandgap_update_alert_threshold(bgp, id, adc_val, hot);
-       spin_unlock(&bgp->lock);
-
-exit:
-       return ret;
-}
-
-/**
- * _ti_bandgap_read_threshold() - helper to read TALERT t_cold or t_hot
- * @bgp: struct ti_bandgap pointer
- * @id: bandgap sensor id
- * @val: value (mCelsius) of a threshold
- * @hot: desired threshold to be read. true if threshold hot, false if
- *       threshold cold
- *
- * It will fetch the required thresholds (hot and cold) for TALERT signal.
- * This function can be used to read t_hot or t_cold, depending on @hot value.
- * Call this function only if bandgap features HAS(TALERT).
- *
- * Return: 0 if no error, -ENOTSUPP if it has no TALERT support, or the
- * corresponding error value if some operation fails.
- */
-static int _ti_bandgap_read_threshold(struct ti_bandgap *bgp, int id,
-                                     int *val, bool hot)
-{
-       struct temp_sensor_registers *tsr;
-       u32 temp, mask;
-       int ret = 0;
-
-       ret = ti_bandgap_validate(bgp, id);
-       if (ret)
-               goto exit;
-
-       if (!TI_BANDGAP_HAS(bgp, TALERT)) {
-               ret = -ENOTSUPP;
-               goto exit;
-       }
-
-       tsr = bgp->conf->sensors[id].registers;
-       if (hot)
-               mask = tsr->threshold_thot_mask;
-       else
-               mask = tsr->threshold_tcold_mask;
-
-       temp = ti_bandgap_readl(bgp, tsr->bgap_threshold);
-       temp = (temp & mask) >> __ffs(mask);
-       ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);
-       if (ret) {
-               dev_err(bgp->dev, "failed to read thot\n");
-               ret = -EIO;
-               goto exit;
-       }
-
-       *val = temp;
-
-exit:
-       return ret;
-}
-
-/***   Exposed APIs   ***/
-
-/**
- * ti_bandgap_read_thot() - reads sensor current thot
- * @bgp: pointer to bandgap instance
- * @id: sensor id
- * @thot: resulting current thot value
- *
- * Return: 0 on success or the proper error code
- */
-int ti_bandgap_read_thot(struct ti_bandgap *bgp, int id, int *thot)
-{
-       return _ti_bandgap_read_threshold(bgp, id, thot, true);
-}
-
-/**
- * ti_bandgap_write_thot() - sets sensor current thot
- * @bgp: pointer to bandgap instance
- * @id: sensor id
- * @val: desired thot value
- *
- * Return: 0 on success or the proper error code
- */
-int ti_bandgap_write_thot(struct ti_bandgap *bgp, int id, int val)
-{
-       return _ti_bandgap_write_threshold(bgp, id, val, true);
-}
-
-/**
- * ti_bandgap_read_tcold() - reads sensor current tcold
- * @bgp: pointer to bandgap instance
- * @id: sensor id
- * @tcold: resulting current tcold value
- *
- * Return: 0 on success or the proper error code
- */
-int ti_bandgap_read_tcold(struct ti_bandgap *bgp, int id, int *tcold)
-{
-       return _ti_bandgap_read_threshold(bgp, id, tcold, false);
-}
-
-/**
- * ti_bandgap_write_tcold() - sets the sensor tcold
- * @bgp: pointer to bandgap instance
- * @id: sensor id
- * @val: desired tcold value
- *
- * Return: 0 on success or the proper error code
- */
-int ti_bandgap_write_tcold(struct ti_bandgap *bgp, int id, int val)
-{
-       return _ti_bandgap_write_threshold(bgp, id, val, false);
-}
-
-/**
- * ti_bandgap_read_counter() - read the sensor counter
- * @bgp: pointer to bandgap instance
- * @id: sensor id
- * @interval: resulting update interval in miliseconds
- */
-static void ti_bandgap_read_counter(struct ti_bandgap *bgp, int id,
-                                   int *interval)
-{
-       struct temp_sensor_registers *tsr;
-       int time;
-
-       tsr = bgp->conf->sensors[id].registers;
-       time = ti_bandgap_readl(bgp, tsr->bgap_counter);
-       time = (time & tsr->counter_mask) >>
-                                       __ffs(tsr->counter_mask);
-       time = time * 1000 / bgp->clk_rate;
-       *interval = time;
-}
-
-/**
- * ti_bandgap_read_counter_delay() - read the sensor counter delay
- * @bgp: pointer to bandgap instance
- * @id: sensor id
- * @interval: resulting update interval in miliseconds
- */
-static void ti_bandgap_read_counter_delay(struct ti_bandgap *bgp, int id,
-                                         int *interval)
-{
-       struct temp_sensor_registers *tsr;
-       int reg_val;
-
-       tsr = bgp->conf->sensors[id].registers;
-
-       reg_val = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
-       reg_val = (reg_val & tsr->mask_counter_delay_mask) >>
-                               __ffs(tsr->mask_counter_delay_mask);
-       switch (reg_val) {
-       case 0:
-               *interval = 0;
-               break;
-       case 1:
-               *interval = 1;
-               break;
-       case 2:
-               *interval = 10;
-               break;
-       case 3:
-               *interval = 100;
-               break;
-       case 4:
-               *interval = 250;
-               break;
-       case 5:
-               *interval = 500;
-               break;
-       default:
-               dev_warn(bgp->dev, "Wrong counter delay value read from register %X",
-                        reg_val);
-       }
-}
-
-/**
- * ti_bandgap_read_update_interval() - read the sensor update interval
- * @bgp: pointer to bandgap instance
- * @id: sensor id
- * @interval: resulting update interval in miliseconds
- *
- * Return: 0 on success or the proper error code
- */
-int ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id,
-                                   int *interval)
-{
-       int ret = 0;
-
-       ret = ti_bandgap_validate(bgp, id);
-       if (ret)
-               goto exit;
-
-       if (!TI_BANDGAP_HAS(bgp, COUNTER) &&
-           !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) {
-               ret = -ENOTSUPP;
-               goto exit;
-       }
-
-       if (TI_BANDGAP_HAS(bgp, COUNTER)) {
-               ti_bandgap_read_counter(bgp, id, interval);
-               goto exit;
-       }
-
-       ti_bandgap_read_counter_delay(bgp, id, interval);
-exit:
-       return ret;
-}
-
-/**
- * ti_bandgap_write_counter_delay() - set the counter_delay
- * @bgp: pointer to bandgap instance
- * @id: sensor id
- * @interval: desired update interval in miliseconds
- *
- * Return: 0 on success or the proper error code
- */
-static int ti_bandgap_write_counter_delay(struct ti_bandgap *bgp, int id,
-                                         u32 interval)
-{
-       int rval;
-
-       switch (interval) {
-       case 0: /* Immediate conversion */
-               rval = 0x0;
-               break;
-       case 1: /* Conversion after ever 1ms */
-               rval = 0x1;
-               break;
-       case 10: /* Conversion after ever 10ms */
-               rval = 0x2;
-               break;
-       case 100: /* Conversion after ever 100ms */
-               rval = 0x3;
-               break;
-       case 250: /* Conversion after ever 250ms */
-               rval = 0x4;
-               break;
-       case 500: /* Conversion after ever 500ms */
-               rval = 0x5;
-               break;
-       default:
-               dev_warn(bgp->dev, "Delay %d ms is not supported\n", interval);
-               return -EINVAL;
-       }
-
-       spin_lock(&bgp->lock);
-       RMW_BITS(bgp, id, bgap_mask_ctrl, mask_counter_delay_mask, rval);
-       spin_unlock(&bgp->lock);
-
-       return 0;
-}
-
-/**
- * ti_bandgap_write_counter() - set the bandgap sensor counter
- * @bgp: pointer to bandgap instance
- * @id: sensor id
- * @interval: desired update interval in miliseconds
- */
-static void ti_bandgap_write_counter(struct ti_bandgap *bgp, int id,
-                                    u32 interval)
-{
-       interval = interval * bgp->clk_rate / 1000;
-       spin_lock(&bgp->lock);
-       RMW_BITS(bgp, id, bgap_counter, counter_mask, interval);
-       spin_unlock(&bgp->lock);
-}
-
-/**
- * ti_bandgap_write_update_interval() - set the update interval
- * @bgp: pointer to bandgap instance
- * @id: sensor id
- * @interval: desired update interval in miliseconds
- *
- * Return: 0 on success or the proper error code
- */
-int ti_bandgap_write_update_interval(struct ti_bandgap *bgp,
-                                    int id, u32 interval)
-{
-       int ret = ti_bandgap_validate(bgp, id);
-       if (ret)
-               goto exit;
-
-       if (!TI_BANDGAP_HAS(bgp, COUNTER) &&
-           !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) {
-               ret = -ENOTSUPP;
-               goto exit;
-       }
-
-       if (TI_BANDGAP_HAS(bgp, COUNTER)) {
-               ti_bandgap_write_counter(bgp, id, interval);
-               goto exit;
-       }
-
-       ret = ti_bandgap_write_counter_delay(bgp, id, interval);
-exit:
-       return ret;
-}
-
-/**
- * ti_bandgap_read_temperature() - report current temperature
- * @bgp: pointer to bandgap instance
- * @id: sensor id
- * @temperature: resulting temperature
- *
- * Return: 0 on success or the proper error code
- */
-int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id,
-                               int *temperature)
-{
-       u32 temp;
-       int ret;
-
-       ret = ti_bandgap_validate(bgp, id);
-       if (ret)
-               return ret;
-
-       spin_lock(&bgp->lock);
-       temp = ti_bandgap_read_temp(bgp, id);
-       spin_unlock(&bgp->lock);
-
-       ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);
-       if (ret)
-               return -EIO;
-
-       *temperature = temp;
-
-       return 0;
-}
-
-/**
- * ti_bandgap_set_sensor_data() - helper function to store thermal
- * framework related data.
- * @bgp: pointer to bandgap instance
- * @id: sensor id
- * @data: thermal framework related data to be stored
- *
- * Return: 0 on success or the proper error code
- */
-int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data)
-{
-       int ret = ti_bandgap_validate(bgp, id);
-       if (ret)
-               return ret;
-
-       bgp->regval[id].data = data;
-
-       return 0;
-}
-
-/**
- * ti_bandgap_get_sensor_data() - helper function to get thermal
- * framework related data.
- * @bgp: pointer to bandgap instance
- * @id: sensor id
- *
- * Return: data stored by set function with sensor id on success or NULL
- */
-void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id)
-{
-       int ret = ti_bandgap_validate(bgp, id);
-       if (ret)
-               return ERR_PTR(ret);
-
-       return bgp->regval[id].data;
-}
-
-/***   Helper functions used during device initialization   ***/
-
-/**
- * ti_bandgap_force_single_read() - executes 1 single ADC conversion
- * @bgp: pointer to struct ti_bandgap
- * @id: sensor id which it is desired to read 1 temperature
- *
- * Used to initialize the conversion state machine and set it to a valid
- * state. Called during device initialization and context restore events.
- *
- * Return: 0
- */
-static int
-ti_bandgap_force_single_read(struct ti_bandgap *bgp, int id)
-{
-       u32 temp = 0, counter = 1000;
-
-       /* Select single conversion mode */
-       if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
-               RMW_BITS(bgp, id, bgap_mode_ctrl, mode_ctrl_mask, 0);
-
-       /* Start of Conversion = 1 */
-       RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 1);
-       /* Wait until DTEMP is updated */
-       temp = ti_bandgap_read_temp(bgp, id);
-
-       while ((temp == 0) && --counter)
-               temp = ti_bandgap_read_temp(bgp, id);
-       /* REVISIT: Check correct condition for end of conversion */
-
-       /* Start of Conversion = 0 */
-       RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 0);
-
-       return 0;
-}
-
-/**
- * ti_bandgap_set_continous_mode() - One time enabling of continuous mode
- * @bgp: pointer to struct ti_bandgap
- *
- * Call this function only if HAS(MODE_CONFIG) is set. As this driver may
- * be used for junction temperature monitoring, it is desirable that the
- * sensors are operational all the time, so that alerts are generated
- * properly.
- *
- * Return: 0
- */
-static int ti_bandgap_set_continuous_mode(struct ti_bandgap *bgp)
-{
-       int i;
-
-       for (i = 0; i < bgp->conf->sensor_count; i++) {
-               /* Perform a single read just before enabling continuous */
-               ti_bandgap_force_single_read(bgp, i);
-               RMW_BITS(bgp, i, bgap_mode_ctrl, mode_ctrl_mask, 1);
-       }
-
-       return 0;
-}
-
-/**
- * ti_bandgap_get_trend() - To fetch the temperature trend of a sensor
- * @bgp: pointer to struct ti_bandgap
- * @id: id of the individual sensor
- * @trend: Pointer to trend.
- *
- * This function needs to be called to fetch the temperature trend of a
- * Particular sensor. The function computes the difference in temperature
- * w.r.t time. For the bandgaps with built in history buffer the temperatures
- * are read from the buffer and for those without the Buffer -ENOTSUPP is
- * returned.
- *
- * Return: 0 if no error, else return corresponding error. If no
- *             error then the trend value is passed on to trend parameter
- */
-int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
-{
-       struct temp_sensor_registers *tsr;
-       u32 temp1, temp2, reg1, reg2;
-       int t1, t2, interval, ret = 0;
-
-       ret = ti_bandgap_validate(bgp, id);
-       if (ret)
-               goto exit;
-
-       if (!TI_BANDGAP_HAS(bgp, HISTORY_BUFFER) ||
-           !TI_BANDGAP_HAS(bgp, FREEZE_BIT)) {
-               ret = -ENOTSUPP;
-               goto exit;
-       }
-
-       tsr = bgp->conf->sensors[id].registers;
-
-       /* Freeze and read the last 2 valid readings */
-       reg1 = tsr->ctrl_dtemp_1;
-       reg2 = tsr->ctrl_dtemp_2;
-
-       /* read temperature from history buffer */
-       temp1 = ti_bandgap_readl(bgp, reg1);
-       temp1 &= tsr->bgap_dtemp_mask;
-
-       temp2 = ti_bandgap_readl(bgp, reg2);
-       temp2 &= tsr->bgap_dtemp_mask;
-
-       /* Convert from adc values to mCelsius temperature */
-       ret = ti_bandgap_adc_to_mcelsius(bgp, temp1, &t1);
-       if (ret)
-               goto exit;
-
-       ret = ti_bandgap_adc_to_mcelsius(bgp, temp2, &t2);
-       if (ret)
-               goto exit;
-
-       /* Fetch the update interval */
-       ret = ti_bandgap_read_update_interval(bgp, id, &interval);
-       if (ret || !interval)
-               goto exit;
-
-       *trend = (t1 - t2) / interval;
-
-       dev_dbg(bgp->dev, "The temperatures are t1 = %d and t2 = %d and trend =%d\n",
-               t1, t2, *trend);
-
-exit:
-       return ret;
-}
-
-/**
- * ti_bandgap_tshut_init() - setup and initialize tshut handling
- * @bgp: pointer to struct ti_bandgap
- * @pdev: pointer to device struct platform_device
- *
- * Call this function only in case the bandgap features HAS(TSHUT).
- * In this case, the driver needs to handle the TSHUT signal as an IRQ.
- * The IRQ is wired as a GPIO, and for this purpose, it is required
- * to specify which GPIO line is used. TSHUT IRQ is fired anytime
- * one of the bandgap sensors violates the TSHUT high/hot threshold.
- * And in that case, the system must go off.
- *
- * Return: 0 if no error, else error status
- */
-static int ti_bandgap_tshut_init(struct ti_bandgap *bgp,
-                                struct platform_device *pdev)
-{
-       int gpio_nr = bgp->tshut_gpio;
-       int status;
-
-       /* Request for gpio_86 line */
-       status = gpio_request(gpio_nr, "tshut");
-       if (status < 0) {
-               dev_err(bgp->dev, "Could not request for TSHUT GPIO:%i\n", 86);
-               return status;
-       }
-       status = gpio_direction_input(gpio_nr);
-       if (status) {
-               dev_err(bgp->dev, "Cannot set input TSHUT GPIO %d\n", gpio_nr);
-               return status;
-       }
-
-       status = request_irq(gpio_to_irq(gpio_nr), ti_bandgap_tshut_irq_handler,
-                            IRQF_TRIGGER_RISING, "tshut", NULL);
-       if (status) {
-               gpio_free(gpio_nr);
-               dev_err(bgp->dev, "request irq failed for TSHUT");
-       }
-
-       return 0;
-}
-
-/**
- * ti_bandgap_alert_init() - setup and initialize talert handling
- * @bgp: pointer to struct ti_bandgap
- * @pdev: pointer to device struct platform_device
- *
- * Call this function only in case the bandgap features HAS(TALERT).
- * In this case, the driver needs to handle the TALERT signals as an IRQs.
- * TALERT is a normal IRQ and it is fired any time thresholds (hot or cold)
- * are violated. In these situation, the driver must reprogram the thresholds,
- * accordingly to specified policy.
- *
- * Return: 0 if no error, else return corresponding error.
- */
-static int ti_bandgap_talert_init(struct ti_bandgap *bgp,
-                                 struct platform_device *pdev)
-{
-       int ret;
-
-       bgp->irq = platform_get_irq(pdev, 0);
-       if (bgp->irq < 0) {
-               dev_err(&pdev->dev, "get_irq failed\n");
-               return bgp->irq;
-       }
-       ret = request_threaded_irq(bgp->irq, NULL,
-                                  ti_bandgap_talert_irq_handler,
-                                  IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
-                                  "talert", bgp);
-       if (ret) {
-               dev_err(&pdev->dev, "Request threaded irq failed.\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-static const struct of_device_id of_ti_bandgap_match[];
-/**
- * ti_bandgap_build() - parse DT and setup a struct ti_bandgap
- * @pdev: pointer to device struct platform_device
- *
- * Used to read the device tree properties accordingly to the bandgap
- * matching version. Based on bandgap version and its capabilities it
- * will build a struct ti_bandgap out of the required DT entries.
- *
- * Return: valid bandgap structure if successful, else returns ERR_PTR
- * return value must be verified with IS_ERR.
- */
-static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev)
-{
-       struct device_node *node = pdev->dev.of_node;
-       const struct of_device_id *of_id;
-       struct ti_bandgap *bgp;
-       struct resource *res;
-       u32 prop;
-       int i;
-
-       /* just for the sake */
-       if (!node) {
-               dev_err(&pdev->dev, "no platform information available\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       bgp = devm_kzalloc(&pdev->dev, sizeof(*bgp), GFP_KERNEL);
-       if (!bgp) {
-               dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n");
-               return ERR_PTR(-ENOMEM);
-       }
-
-       of_id = of_match_device(of_ti_bandgap_match, &pdev->dev);
-       if (of_id)
-               bgp->conf = of_id->data;
-
-       /* register shadow for context save and restore */
-       bgp->regval = devm_kzalloc(&pdev->dev, sizeof(*bgp->regval) *
-                                  bgp->conf->sensor_count, GFP_KERNEL);
-       if (!bgp) {
-               dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n");
-               return ERR_PTR(-ENOMEM);
-       }
-
-       i = 0;
-       do {
-               void __iomem *chunk;
-
-               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-               if (!res)
-                       break;
-               chunk = devm_ioremap_resource(&pdev->dev, res);
-               if (i == 0)
-                       bgp->base = chunk;
-               if (IS_ERR(chunk))
-                       return ERR_CAST(chunk);
-
-               i++;
-       } 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;
-               if (!gpio_is_valid(bgp->tshut_gpio)) {
-                       dev_err(&pdev->dev, "invalid gpio for tshut (%d)\n",
-                               bgp->tshut_gpio);
-                       return ERR_PTR(-EINVAL);
-               }
-       }
-
-       return bgp;
-}
-
-/***   Device driver call backs   ***/
-
-static
-int ti_bandgap_probe(struct platform_device *pdev)
-{
-       struct ti_bandgap *bgp;
-       int clk_rate, ret = 0, i;
-
-       bgp = ti_bandgap_build(pdev);
-       if (IS_ERR_OR_NULL(bgp)) {
-               dev_err(&pdev->dev, "failed to fetch platform data\n");
-               return PTR_ERR(bgp);
-       }
-       bgp->dev = &pdev->dev;
-
-       if (TI_BANDGAP_HAS(bgp, TSHUT)) {
-               ret = ti_bandgap_tshut_init(bgp, pdev);
-               if (ret) {
-                       dev_err(&pdev->dev,
-                               "failed to initialize system tshut IRQ\n");
-                       return ret;
-               }
-       }
-
-       bgp->fclock = clk_get(NULL, bgp->conf->fclock_name);
-       ret = IS_ERR_OR_NULL(bgp->fclock);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to request fclock reference\n");
-               goto free_irqs;
-       }
-
-       bgp->div_clk = clk_get(NULL,  bgp->conf->div_ck_name);
-       ret = IS_ERR_OR_NULL(bgp->div_clk);
-       if (ret) {
-               dev_err(&pdev->dev,
-                       "failed to request div_ts_ck clock ref\n");
-               goto free_irqs;
-       }
-
-       for (i = 0; i < bgp->conf->sensor_count; i++) {
-               struct temp_sensor_registers *tsr;
-               u32 val;
-
-               tsr = bgp->conf->sensors[i].registers;
-               /*
-                * check if the efuse has a non-zero value if not
-                * it is an untrimmed sample and the temperatures
-                * may not be accurate
-                */
-               val = ti_bandgap_readl(bgp, tsr->bgap_efuse);
-               if (ret || !val)
-                       dev_info(&pdev->dev,
-                                "Non-trimmed BGAP, Temp not accurate\n");
-       }
-
-       clk_rate = clk_round_rate(bgp->div_clk,
-                                 bgp->conf->sensors[0].ts_data->max_freq);
-       if (clk_rate < bgp->conf->sensors[0].ts_data->min_freq ||
-           clk_rate == 0xffffffff) {
-               ret = -ENODEV;
-               dev_err(&pdev->dev, "wrong clock rate (%d)\n", clk_rate);
-               goto put_clks;
-       }
-
-       ret = clk_set_rate(bgp->div_clk, clk_rate);
-       if (ret)
-               dev_err(&pdev->dev, "Cannot re-set clock rate. Continuing\n");
-
-       bgp->clk_rate = clk_rate;
-       if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
-               clk_prepare_enable(bgp->fclock);
-
-
-       spin_lock_init(&bgp->lock);
-       bgp->dev = &pdev->dev;
-       platform_set_drvdata(pdev, bgp);
-
-       ti_bandgap_power(bgp, true);
-
-       /* Set default counter to 1 for now */
-       if (TI_BANDGAP_HAS(bgp, COUNTER))
-               for (i = 0; i < bgp->conf->sensor_count; i++)
-                       RMW_BITS(bgp, i, bgap_counter, counter_mask, 1);
-
-       /* Set default thresholds for alert and shutdown */
-       for (i = 0; i < bgp->conf->sensor_count; i++) {
-               struct temp_sensor_data *ts_data;
-
-               ts_data = bgp->conf->sensors[i].ts_data;
-
-               if (TI_BANDGAP_HAS(bgp, TALERT)) {
-                       /* Set initial Talert thresholds */
-                       RMW_BITS(bgp, i, bgap_threshold,
-                                threshold_tcold_mask, ts_data->t_cold);
-                       RMW_BITS(bgp, i, bgap_threshold,
-                                threshold_thot_mask, ts_data->t_hot);
-                       /* Enable the alert events */
-                       RMW_BITS(bgp, i, bgap_mask_ctrl, mask_hot_mask, 1);
-                       RMW_BITS(bgp, i, bgap_mask_ctrl, mask_cold_mask, 1);
-               }
-
-               if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) {
-                       /* Set initial Tshut thresholds */
-                       RMW_BITS(bgp, i, tshut_threshold,
-                                tshut_hot_mask, ts_data->tshut_hot);
-                       RMW_BITS(bgp, i, tshut_threshold,
-                                tshut_cold_mask, ts_data->tshut_cold);
-               }
-       }
-
-       if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
-               ti_bandgap_set_continuous_mode(bgp);
-
-       /* Set .250 seconds time as default counter */
-       if (TI_BANDGAP_HAS(bgp, COUNTER))
-               for (i = 0; i < bgp->conf->sensor_count; i++)
-                       RMW_BITS(bgp, i, bgap_counter, counter_mask,
-                                bgp->clk_rate / 4);
-
-       /* Every thing is good? Then expose the sensors */
-       for (i = 0; i < bgp->conf->sensor_count; i++) {
-               char *domain;
-
-               if (bgp->conf->sensors[i].register_cooling) {
-                       ret = bgp->conf->sensors[i].register_cooling(bgp, i);
-                       if (ret)
-                               goto remove_sensors;
-               }
-
-               if (bgp->conf->expose_sensor) {
-                       domain = bgp->conf->sensors[i].domain;
-                       ret = bgp->conf->expose_sensor(bgp, i, domain);
-                       if (ret)
-                               goto remove_last_cooling;
-               }
-       }
-
-       /*
-        * Enable the Interrupts once everything is set. Otherwise irq handler
-        * might be called as soon as it is enabled where as rest of framework
-        * is still getting initialised.
-        */
-       if (TI_BANDGAP_HAS(bgp, TALERT)) {
-               ret = ti_bandgap_talert_init(bgp, pdev);
-               if (ret) {
-                       dev_err(&pdev->dev, "failed to initialize Talert IRQ\n");
-                       i = bgp->conf->sensor_count;
-                       goto disable_clk;
-               }
-       }
-
-       return 0;
-
-remove_last_cooling:
-       if (bgp->conf->sensors[i].unregister_cooling)
-               bgp->conf->sensors[i].unregister_cooling(bgp, i);
-remove_sensors:
-       for (i--; i >= 0; i--) {
-               if (bgp->conf->sensors[i].unregister_cooling)
-                       bgp->conf->sensors[i].unregister_cooling(bgp, i);
-               if (bgp->conf->remove_sensor)
-                       bgp->conf->remove_sensor(bgp, i);
-       }
-       ti_bandgap_power(bgp, false);
-disable_clk:
-       if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
-               clk_disable_unprepare(bgp->fclock);
-put_clks:
-       clk_put(bgp->fclock);
-       clk_put(bgp->div_clk);
-free_irqs:
-       if (TI_BANDGAP_HAS(bgp, TSHUT)) {
-               free_irq(gpio_to_irq(bgp->tshut_gpio), NULL);
-               gpio_free(bgp->tshut_gpio);
-       }
-
-       return ret;
-}
-
-static
-int ti_bandgap_remove(struct platform_device *pdev)
-{
-       struct ti_bandgap *bgp = platform_get_drvdata(pdev);
-       int i;
-
-       /* First thing is to remove sensor interfaces */
-       for (i = 0; i < bgp->conf->sensor_count; i++) {
-               if (bgp->conf->sensors[i].unregister_cooling)
-                       bgp->conf->sensors[i].unregister_cooling(bgp, i);
-
-               if (bgp->conf->remove_sensor)
-                       bgp->conf->remove_sensor(bgp, i);
-       }
-
-       ti_bandgap_power(bgp, false);
-
-       if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
-               clk_disable_unprepare(bgp->fclock);
-       clk_put(bgp->fclock);
-       clk_put(bgp->div_clk);
-
-       if (TI_BANDGAP_HAS(bgp, TALERT))
-               free_irq(bgp->irq, bgp);
-
-       if (TI_BANDGAP_HAS(bgp, TSHUT)) {
-               free_irq(gpio_to_irq(bgp->tshut_gpio), NULL);
-               gpio_free(bgp->tshut_gpio);
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int ti_bandgap_save_ctxt(struct ti_bandgap *bgp)
-{
-       int i;
-
-       for (i = 0; i < bgp->conf->sensor_count; i++) {
-               struct temp_sensor_registers *tsr;
-               struct temp_sensor_regval *rval;
-
-               rval = &bgp->regval[i];
-               tsr = bgp->conf->sensors[i].registers;
-
-               if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
-                       rval->bg_mode_ctrl = ti_bandgap_readl(bgp,
-                                                       tsr->bgap_mode_ctrl);
-               if (TI_BANDGAP_HAS(bgp, COUNTER))
-                       rval->bg_counter = ti_bandgap_readl(bgp,
-                                                       tsr->bgap_counter);
-               if (TI_BANDGAP_HAS(bgp, TALERT)) {
-                       rval->bg_threshold = ti_bandgap_readl(bgp,
-                                                       tsr->bgap_threshold);
-                       rval->bg_ctrl = ti_bandgap_readl(bgp,
-                                                  tsr->bgap_mask_ctrl);
-               }
-
-               if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG))
-                       rval->tshut_threshold = ti_bandgap_readl(bgp,
-                                                  tsr->tshut_threshold);
-       }
-
-       return 0;
-}
-
-static int ti_bandgap_restore_ctxt(struct ti_bandgap *bgp)
-{
-       int i;
-
-       for (i = 0; i < bgp->conf->sensor_count; i++) {
-               struct temp_sensor_registers *tsr;
-               struct temp_sensor_regval *rval;
-               u32 val = 0;
-
-               rval = &bgp->regval[i];
-               tsr = bgp->conf->sensors[i].registers;
-
-               if (TI_BANDGAP_HAS(bgp, COUNTER))
-                       val = ti_bandgap_readl(bgp, tsr->bgap_counter);
-
-               if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG))
-                       ti_bandgap_writel(bgp, rval->tshut_threshold,
-                                         tsr->tshut_threshold);
-               /* Force immediate temperature measurement and update
-                * of the DTEMP field
-                */
-               ti_bandgap_force_single_read(bgp, i);
-
-               if (TI_BANDGAP_HAS(bgp, COUNTER))
-                       ti_bandgap_writel(bgp, rval->bg_counter,
-                                         tsr->bgap_counter);
-               if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
-                       ti_bandgap_writel(bgp, rval->bg_mode_ctrl,
-                                         tsr->bgap_mode_ctrl);
-               if (TI_BANDGAP_HAS(bgp, TALERT)) {
-                       ti_bandgap_writel(bgp, rval->bg_threshold,
-                                         tsr->bgap_threshold);
-                       ti_bandgap_writel(bgp, rval->bg_ctrl,
-                                         tsr->bgap_mask_ctrl);
-               }
-       }
-
-       return 0;
-}
-
-static int ti_bandgap_suspend(struct device *dev)
-{
-       struct ti_bandgap *bgp = dev_get_drvdata(dev);
-       int err;
-
-       err = ti_bandgap_save_ctxt(bgp);
-       ti_bandgap_power(bgp, false);
-
-       if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
-               clk_disable_unprepare(bgp->fclock);
-
-       return err;
-}
-
-static int ti_bandgap_resume(struct device *dev)
-{
-       struct ti_bandgap *bgp = dev_get_drvdata(dev);
-
-       if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
-               clk_prepare_enable(bgp->fclock);
-
-       ti_bandgap_power(bgp, true);
-
-       return ti_bandgap_restore_ctxt(bgp);
-}
-static const struct dev_pm_ops ti_bandgap_dev_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(ti_bandgap_suspend,
-                               ti_bandgap_resume)
-};
-
-#define DEV_PM_OPS     (&ti_bandgap_dev_pm_ops)
-#else
-#define DEV_PM_OPS     NULL
-#endif
-
-static const struct of_device_id of_ti_bandgap_match[] = {
-#ifdef CONFIG_OMAP4_THERMAL
-       {
-               .compatible = "ti,omap4430-bandgap",
-               .data = (void *)&omap4430_data,
-       },
-       {
-               .compatible = "ti,omap4460-bandgap",
-               .data = (void *)&omap4460_data,
-       },
-       {
-               .compatible = "ti,omap4470-bandgap",
-               .data = (void *)&omap4470_data,
-       },
-#endif
-#ifdef CONFIG_OMAP5_THERMAL
-       {
-               .compatible = "ti,omap5430-bandgap",
-               .data = (void *)&omap5430_data,
-       },
-#endif
-       /* Sentinel */
-       { },
-};
-MODULE_DEVICE_TABLE(of, of_ti_bandgap_match);
-
-static struct platform_driver ti_bandgap_sensor_driver = {
-       .probe = ti_bandgap_probe,
-       .remove = ti_bandgap_remove,
-       .driver = {
-                       .name = "ti-soc-thermal",
-                       .pm = DEV_PM_OPS,
-                       .of_match_table = of_ti_bandgap_match,
-       },
-};
-
-module_platform_driver(ti_bandgap_sensor_driver);
-
-MODULE_DESCRIPTION("OMAP4+ bandgap temperature sensor driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:ti-soc-thermal");
-MODULE_AUTHOR("Texas Instrument Inc.");
diff --git a/drivers/staging/ti-soc-thermal/ti-bandgap.h b/drivers/staging/ti-soc-thermal/ti-bandgap.h
deleted file mode 100644 (file)
index 5f4794a..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * OMAP4 Bandgap temperature sensor driver
- *
- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
- * Contact:
- *   Eduardo Valentin <eduardo.valentin@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-#ifndef __TI_BANDGAP_H
-#define __TI_BANDGAP_H
-
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/err.h>
-
-/**
- * DOC: bandgap driver data structure
- * ==================================
- *
- *   +----------+----------------+
- *   | struct temp_sensor_regval |
- *   +---------------------------+
- *              * (Array of)
- *              |
- *              |
- *   +-------------------+   +-----------------+
- *   | struct ti_bandgap |-->| struct device * |
- *   +----------+--------+   +-----------------+
- *              |
- *              |
- *              V
- *   +------------------------+
- *   | struct ti_bandgap_data |
- *   +------------------------+
- *              |
- *              |
- *              * (Array of)
- * +------------+------------------------------------------------------+
- * | +----------+------------+   +-------------------------+           |
- * | | struct ti_temp_sensor |-->| struct temp_sensor_data |           |
- * | +-----------------------+   +------------+------------+           |
- * |            |                                                      |
- * |            +                                                      |
- * |            V                                                      |
- * | +----------+-------------------+                                  |
- * | | struct temp_sensor_registers |                                  |
- * | +------------------------------+                                  |
- * |                                                                   |
- * +-------------------------------------------------------------------+
- *
- * Above is a simple diagram describing how the data structure below
- * are organized. For each bandgap device there should be a ti_bandgap_data
- * containing the device instance configuration, as well as, an array of
- * sensors, representing every sensor instance present in this bandgap.
- */
-
-/**
- * struct temp_sensor_registers - descriptor to access registers and bitfields
- * @temp_sensor_ctrl: TEMP_SENSOR_CTRL register offset
- * @bgap_tempsoff_mask: mask to temp_sensor_ctrl.tempsoff
- * @bgap_soc_mask: mask to temp_sensor_ctrl.soc
- * @bgap_eocz_mask: mask to temp_sensor_ctrl.eocz
- * @bgap_dtemp_mask: mask to temp_sensor_ctrl.dtemp
- * @bgap_mask_ctrl: BANDGAP_MASK_CTRL register offset
- * @mask_hot_mask: mask to bandgap_mask_ctrl.mask_hot
- * @mask_cold_mask: mask to bandgap_mask_ctrl.mask_cold
- * @mask_sidlemode_mask: mask to bandgap_mask_ctrl.mask_sidlemode
- * @mask_counter_delay_mask: mask to bandgap_mask_ctrl.mask_counter_delay
- * @mask_freeze_mask: mask to bandgap_mask_ctrl.mask_free
- * @mask_clear_mask: mask to bandgap_mask_ctrl.mask_clear
- * @mask_clear_accum_mask: mask to bandgap_mask_ctrl.mask_clear_accum
- * @bgap_mode_ctrl: BANDGAP_MODE_CTRL register offset
- * @mode_ctrl_mask: mask to bandgap_mode_ctrl.mode_ctrl
- * @bgap_counter: BANDGAP_COUNTER register offset
- * @counter_mask: mask to bandgap_counter.counter
- * @bgap_threshold: BANDGAP_THRESHOLD register offset (TALERT thresholds)
- * @threshold_thot_mask: mask to bandgap_threhold.thot
- * @threshold_tcold_mask: mask to bandgap_threhold.tcold
- * @tshut_threshold: TSHUT_THRESHOLD register offset (TSHUT thresholds)
- * @tshut_efuse_mask: mask to tshut_threshold.tshut_efuse
- * @tshut_efuse_shift: shift to tshut_threshold.tshut_efuse
- * @tshut_hot_mask: mask to tshut_threhold.thot
- * @tshut_cold_mask: mask to tshut_threhold.thot
- * @bgap_status: BANDGAP_STATUS register offset
- * @status_clean_stop_mask: mask to bandgap_status.clean_stop
- * @status_bgap_alert_mask: mask to bandgap_status.bandgap_alert
- * @status_hot_mask: mask to bandgap_status.hot
- * @status_cold_mask: mask to bandgap_status.cold
- * @bgap_cumul_dtemp: BANDGAP_CUMUL_DTEMP register offset
- * @ctrl_dtemp_0: CTRL_DTEMP0 register offset
- * @ctrl_dtemp_1: CTRL_DTEMP1 register offset
- * @ctrl_dtemp_2: CTRL_DTEMP2 register offset
- * @ctrl_dtemp_3: CTRL_DTEMP3 register offset
- * @ctrl_dtemp_4: CTRL_DTEMP4 register offset
- * @bgap_efuse: BANDGAP_EFUSE register offset
- *
- * The register offsets and bitfields might change across
- * OMAP and variants versions. Hence this struct serves as a
- * descriptor map on how to access the registers and the bitfields.
- *
- * This descriptor contains registers of all versions of bandgap chips.
- * Not all versions will use all registers, depending on the available
- * features. Please read TRMs for descriptive explanation on each bitfield.
- */
-
-struct temp_sensor_registers {
-       u32     temp_sensor_ctrl;
-       u32     bgap_tempsoff_mask;
-       u32     bgap_soc_mask;
-       u32     bgap_eocz_mask; /* not used: but needs revisit */
-       u32     bgap_dtemp_mask;
-
-       u32     bgap_mask_ctrl;
-       u32     mask_hot_mask;
-       u32     mask_cold_mask;
-       u32     mask_sidlemode_mask; /* not used: but may be needed for pm */
-       u32     mask_counter_delay_mask;
-       u32     mask_freeze_mask;
-       u32     mask_clear_mask; /* not used: but needed for trending */
-       u32     mask_clear_accum_mask; /* not used: but needed for trending */
-
-       u32     bgap_mode_ctrl;
-       u32     mode_ctrl_mask;
-
-       u32     bgap_counter;
-       u32     counter_mask;
-
-       u32     bgap_threshold;
-       u32     threshold_thot_mask;
-       u32     threshold_tcold_mask;
-
-       u32     tshut_threshold;
-       u32     tshut_efuse_mask; /* not used */
-       u32     tshut_efuse_shift; /* not used */
-       u32     tshut_hot_mask;
-       u32     tshut_cold_mask;
-
-       u32     bgap_status;
-       u32     status_clean_stop_mask; /* not used: but needed for trending */
-       u32     status_bgap_alert_mask; /* not used */
-       u32     status_hot_mask;
-       u32     status_cold_mask;
-
-       u32     bgap_cumul_dtemp; /* not used: but needed for trending */
-       u32     ctrl_dtemp_0; /* not used: but needed for trending */
-       u32     ctrl_dtemp_1; /* not used: but needed for trending */
-       u32     ctrl_dtemp_2; /* not used: but needed for trending */
-       u32     ctrl_dtemp_3; /* not used: but needed for trending */
-       u32     ctrl_dtemp_4; /* not used: but needed for trending */
-       u32     bgap_efuse;
-};
-
-/**
- * struct temp_sensor_data - The thresholds and limits for temperature sensors.
- * @tshut_hot: temperature to trigger a thermal reset (initial value)
- * @tshut_cold: temp to get the plat out of reset due to thermal (init val)
- * @t_hot: temperature to trigger a thermal alert (high initial value)
- * @t_cold: temperature to trigger a thermal alert (low initial value)
- * @min_freq: sensor minimum clock rate
- * @max_freq: sensor maximum clock rate
- * @max_temp: sensor maximum temperature
- * @min_temp: sensor minimum temperature
- * @hyst_val: temperature hysteresis considered while converting ADC values
- * @update_int1: update interval
- * @update_int2: update interval
- *
- * This data structure will hold the required thresholds and temperature limits
- * for a specific temperature sensor, like shutdown temperature, alert
- * temperature, clock / rate used, ADC conversion limits and update intervals
- */
-struct temp_sensor_data {
-       u32     tshut_hot;
-       u32     tshut_cold;
-       u32     t_hot;
-       u32     t_cold;
-       u32     min_freq;
-       u32     max_freq;
-       int     max_temp;
-       int     min_temp;
-       int     hyst_val;
-       u32     update_int1; /* not used */
-       u32     update_int2; /* not used */
-};
-
-struct ti_bandgap_data;
-
-/**
- * struct temp_sensor_regval - temperature sensor register values and priv data
- * @bg_mode_ctrl: temp sensor control register value
- * @bg_ctrl: bandgap ctrl register value
- * @bg_counter: bandgap counter value
- * @bg_threshold: bandgap threshold register value
- * @tshut_threshold: bandgap tshut register value
- * @data: private data
- *
- * Data structure to save and restore bandgap register set context. Only
- * required registers are shadowed, when needed.
- */
-struct temp_sensor_regval {
-       u32                     bg_mode_ctrl;
-       u32                     bg_ctrl;
-       u32                     bg_counter;
-       u32                     bg_threshold;
-       u32                     tshut_threshold;
-       void                    *data;
-};
-
-/**
- * struct ti_bandgap - bandgap device structure
- * @dev: struct device pointer
- * @base: io memory base address
- * @conf: struct with bandgap configuration set (# sensors, conv_table, etc)
- * @regval: temperature sensor register values
- * @fclock: pointer to functional clock of temperature sensor
- * @div_clk: pointer to divider clock of temperature sensor fclk
- * @lock: spinlock for ti_bandgap structure
- * @irq: MPU IRQ number for thermal alert
- * @tshut_gpio: GPIO where Tshut signal is routed
- * @clk_rate: Holds current clock rate
- *
- * The bandgap device structure representing the bandgap device instance.
- * It holds most of the dynamic stuff. Configurations and sensor specific
- * entries are inside the @conf structure.
- */
-struct ti_bandgap {
-       struct device                   *dev;
-       void __iomem                    *base;
-       const struct ti_bandgap_data    *conf;
-       struct temp_sensor_regval       *regval;
-       struct clk                      *fclock;
-       struct clk                      *div_clk;
-       spinlock_t                      lock; /* shields this struct */
-       int                             irq;
-       int                             tshut_gpio;
-       u32                             clk_rate;
-};
-
-/**
- * struct ti_temp_sensor - bandgap temperature sensor configuration data
- * @ts_data: pointer to struct with thresholds, limits of temperature sensor
- * @registers: pointer to the list of register offsets and bitfields
- * @domain: the name of the domain where the sensor is located
- * @slope: sensor gradient slope info for hotspot extrapolation equation
- * @constant: sensor gradient const info for hotspot extrapolation equation
- * @slope_pcb: sensor gradient slope info for hotspot extrapolation equation
- *             with no external influence
- * @constant_pcb: sensor gradient const info for hotspot extrapolation equation
- *             with no external influence
- * @register_cooling: function to describe how this sensor is going to be cooled
- * @unregister_cooling: function to release cooling data
- *
- * Data structure to describe a temperature sensor handled by a bandgap device.
- * It should provide configuration details on this sensor, such as how to
- * access the registers affecting this sensor, shadow register buffer, how to
- * assess the gradient from hotspot, how to cooldown the domain when sensor
- * reports too hot temperature.
- */
-struct ti_temp_sensor {
-       struct temp_sensor_data         *ts_data;
-       struct temp_sensor_registers    *registers;
-       char                            *domain;
-       /* for hotspot extrapolation */
-       const int                       slope;
-       const int                       constant;
-       const int                       slope_pcb;
-       const int                       constant_pcb;
-       int (*register_cooling)(struct ti_bandgap *bgp, int id);
-       int (*unregister_cooling)(struct ti_bandgap *bgp, int id);
-};
-
-/**
- * DOC: ti bandgap feature types
- *
- * TI_BANDGAP_FEATURE_TSHUT - used when the thermal shutdown signal output
- *      of a bandgap device instance is routed to the processor. This means
- *      the system must react and perform the shutdown by itself (handle an
- *      IRQ, for instance).
- *
- * TI_BANDGAP_FEATURE_TSHUT_CONFIG - used when the bandgap device has control
- *      over the thermal shutdown configuration. This means that the thermal
- *      shutdown thresholds are programmable, for instance.
- *
- * TI_BANDGAP_FEATURE_TALERT - used when the bandgap device instance outputs
- *      a signal representing violation of programmable alert thresholds.
- *
- * TI_BANDGAP_FEATURE_MODE_CONFIG - used when it is possible to choose which
- *      mode, continuous or one shot, the bandgap device instance will operate.
- *
- * TI_BANDGAP_FEATURE_COUNTER - used when the bandgap device instance allows
- *      programming the update interval of its internal state machine.
- *
- * TI_BANDGAP_FEATURE_POWER_SWITCH - used when the bandgap device allows
- *      itself to be switched on/off.
- *
- * TI_BANDGAP_FEATURE_CLK_CTRL - used when the clocks feeding the bandgap
- *      device are gateable or not.
- *
- * TI_BANDGAP_FEATURE_FREEZE_BIT - used when the bandgap device features
- *      a history buffer that its update can be freezed/unfreezed.
- *
- * TI_BANDGAP_FEATURE_COUNTER_DELAY - used when the bandgap device features
- *     a delay programming based on distinct values.
- *
- * TI_BANDGAP_FEATURE_HISTORY_BUFFER - used when the bandgap device features
- *     a history buffer of temperatures.
- *
- * TI_BANDGAP_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 TI_BANDGAP_FEATURE_TSHUT               BIT(0)
-#define TI_BANDGAP_FEATURE_TSHUT_CONFIG                BIT(1)
-#define TI_BANDGAP_FEATURE_TALERT              BIT(2)
-#define TI_BANDGAP_FEATURE_MODE_CONFIG         BIT(3)
-#define TI_BANDGAP_FEATURE_COUNTER             BIT(4)
-#define TI_BANDGAP_FEATURE_POWER_SWITCH                BIT(5)
-#define TI_BANDGAP_FEATURE_CLK_CTRL            BIT(6)
-#define TI_BANDGAP_FEATURE_FREEZE_BIT          BIT(7)
-#define TI_BANDGAP_FEATURE_COUNTER_DELAY       BIT(8)
-#define TI_BANDGAP_FEATURE_HISTORY_BUFFER      BIT(9)
-#define TI_BANDGAP_HAS(b, f)                   \
-                       ((b)->conf->features & TI_BANDGAP_FEATURE_ ## f)
-
-/**
- * struct ti_bandgap_data - ti bandgap data configuration structure
- * @features: a bitwise flag set to describe the device features
- * @conv_table: Pointer to ADC to temperature conversion table
- * @adc_start_val: ADC conversion table starting value
- * @adc_end_val: ADC conversion table ending value
- * @fclock_name: clock name of the functional clock
- * @div_ck_name: clock name of the clock divisor
- * @sensor_count: count of temperature sensor within this bandgap device
- * @report_temperature: callback to report thermal alert to thermal API
- * @expose_sensor: callback to export sensor to thermal API
- * @remove_sensor: callback to destroy sensor from thermal API
- * @sensors: array of sensors present in this bandgap instance
- *
- * This is a data structure which should hold most of the static configuration
- * of a bandgap device instance. It should describe which features this instance
- * is capable of, the clock names to feed this device, the amount of sensors and
- * their configuration representation, and how to export and unexport them to
- * a thermal API.
- */
-struct ti_bandgap_data {
-       unsigned int                    features;
-       const int                       *conv_table;
-       u32                             adc_start_val;
-       u32                             adc_end_val;
-       char                            *fclock_name;
-       char                            *div_ck_name;
-       int                             sensor_count;
-       int (*report_temperature)(struct ti_bandgap *bgp, int id);
-       int (*expose_sensor)(struct ti_bandgap *bgp, int id, char *domain);
-       int (*remove_sensor)(struct ti_bandgap *bgp, int id);
-
-       /* this needs to be at the end */
-       struct ti_temp_sensor           sensors[];
-};
-
-int ti_bandgap_read_thot(struct ti_bandgap *bgp, int id, int *thot);
-int ti_bandgap_write_thot(struct ti_bandgap *bgp, int id, int val);
-int ti_bandgap_read_tcold(struct ti_bandgap *bgp, int id, int *tcold);
-int ti_bandgap_write_tcold(struct ti_bandgap *bgp, int id, int val);
-int ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id,
-                                   int *interval);
-int ti_bandgap_write_update_interval(struct ti_bandgap *bgp, int id,
-                                    u32 interval);
-int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id,
-                                 int *temperature);
-int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data);
-void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id);
-int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend);
-
-#ifdef CONFIG_OMAP4_THERMAL
-extern const struct ti_bandgap_data omap4430_data;
-extern const struct ti_bandgap_data omap4460_data;
-extern const struct ti_bandgap_data omap4470_data;
-#else
-#define omap4430_data                                  NULL
-#define omap4460_data                                  NULL
-#define omap4470_data                                  NULL
-#endif
-
-#ifdef CONFIG_OMAP5_THERMAL
-extern const struct ti_bandgap_data omap5430_data;
-#else
-#define omap5430_data                                  NULL
-#endif
-
-#endif
diff --git a/drivers/staging/ti-soc-thermal/ti-thermal-common.c b/drivers/staging/ti-soc-thermal/ti-thermal-common.c
deleted file mode 100644 (file)
index 8e67ebf..0000000
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * OMAP thermal driver interface
- *
- * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
- * Contact:
- *   Eduardo Valentin <eduardo.valentin@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/mutex.h>
-#include <linux/gfp.h>
-#include <linux/kernel.h>
-#include <linux/workqueue.h>
-#include <linux/thermal.h>
-#include <linux/cpufreq.h>
-#include <linux/cpumask.h>
-#include <linux/cpu_cooling.h>
-
-#include "ti-thermal.h"
-#include "ti-bandgap.h"
-
-/* common data structures */
-struct ti_thermal_data {
-       struct thermal_zone_device *ti_thermal;
-       struct thermal_zone_device *pcb_tz;
-       struct thermal_cooling_device *cool_dev;
-       struct ti_bandgap *bgp;
-       enum thermal_device_mode mode;
-       struct work_struct thermal_wq;
-       int sensor_id;
-};
-
-static void ti_thermal_work(struct work_struct *work)
-{
-       struct ti_thermal_data *data = container_of(work,
-                                       struct ti_thermal_data, thermal_wq);
-
-       thermal_zone_device_update(data->ti_thermal);
-
-       dev_dbg(&data->ti_thermal->device, "updated thermal zone %s\n",
-               data->ti_thermal->type);
-}
-
-/**
- * ti_thermal_hotspot_temperature - returns sensor extrapolated temperature
- * @t: omap sensor temperature
- * @s: omap sensor slope value
- * @c: omap sensor const value
- */
-static inline int ti_thermal_hotspot_temperature(int t, int s, int c)
-{
-       int delta = t * s / 1000 + c;
-
-       if (delta < 0)
-               delta = 0;
-
-       return t + delta;
-}
-
-/* thermal zone ops */
-/* Get temperature callback function for thermal zone*/
-static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
-                                     unsigned long *temp)
-{
-       struct thermal_zone_device *pcb_tz = NULL;
-       struct ti_thermal_data *data = thermal->devdata;
-       struct ti_bandgap *bgp;
-       const struct ti_temp_sensor *s;
-       int ret, tmp, slope, constant;
-       unsigned long pcb_temp;
-
-       if (!data)
-               return 0;
-
-       bgp = data->bgp;
-       s = &bgp->conf->sensors[data->sensor_id];
-
-       ret = ti_bandgap_read_temperature(bgp, data->sensor_id, &tmp);
-       if (ret)
-               return ret;
-
-       /* Default constants */
-       slope = s->slope;
-       constant = s->constant;
-
-       pcb_tz = data->pcb_tz;
-       /* In case pcb zone is available, use the extrapolation rule with it */
-       if (!IS_ERR_OR_NULL(pcb_tz)) {
-               ret = thermal_zone_get_temp(pcb_tz, &pcb_temp);
-               if (!ret) {
-                       tmp -= pcb_temp; /* got a valid PCB temp */
-                       slope = s->slope_pcb;
-                       constant = s->constant_pcb;
-               } else {
-                       dev_err(bgp->dev,
-                               "Failed to read PCB state. Using defaults\n");
-               }
-       }
-       *temp = ti_thermal_hotspot_temperature(tmp, slope, constant);
-
-       return ret;
-}
-
-/* Bind callback functions for thermal zone */
-static int ti_thermal_bind(struct thermal_zone_device *thermal,
-                          struct thermal_cooling_device *cdev)
-{
-       struct ti_thermal_data *data = thermal->devdata;
-       int id;
-
-       if (IS_ERR_OR_NULL(data))
-               return -ENODEV;
-
-       /* check if this is the cooling device we registered */
-       if (data->cool_dev != cdev)
-               return 0;
-
-       id = data->sensor_id;
-
-       /* Simple thing, two trips, one passive another critical */
-       return thermal_zone_bind_cooling_device(thermal, 0, cdev,
-       /* bind with min and max states defined by cpu_cooling */
-                                               THERMAL_NO_LIMIT,
-                                               THERMAL_NO_LIMIT);
-}
-
-/* Unbind callback functions for thermal zone */
-static int ti_thermal_unbind(struct thermal_zone_device *thermal,
-                            struct thermal_cooling_device *cdev)
-{
-       struct ti_thermal_data *data = thermal->devdata;
-
-       if (IS_ERR_OR_NULL(data))
-               return -ENODEV;
-
-       /* check if this is the cooling device we registered */
-       if (data->cool_dev != cdev)
-               return 0;
-
-       /* Simple thing, two trips, one passive another critical */
-       return thermal_zone_unbind_cooling_device(thermal, 0, cdev);
-}
-
-/* Get mode callback functions for thermal zone */
-static int ti_thermal_get_mode(struct thermal_zone_device *thermal,
-                              enum thermal_device_mode *mode)
-{
-       struct ti_thermal_data *data = thermal->devdata;
-
-       if (data)
-               *mode = data->mode;
-
-       return 0;
-}
-
-/* Set mode callback functions for thermal zone */
-static int ti_thermal_set_mode(struct thermal_zone_device *thermal,
-                              enum thermal_device_mode mode)
-{
-       struct ti_thermal_data *data = thermal->devdata;
-
-       if (!data->ti_thermal) {
-               dev_notice(&thermal->device, "thermal zone not registered\n");
-               return 0;
-       }
-
-       mutex_lock(&data->ti_thermal->lock);
-
-       if (mode == THERMAL_DEVICE_ENABLED)
-               data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
-       else
-               data->ti_thermal->polling_delay = 0;
-
-       mutex_unlock(&data->ti_thermal->lock);
-
-       data->mode = mode;
-       thermal_zone_device_update(data->ti_thermal);
-       dev_dbg(&thermal->device, "thermal polling set for duration=%d msec\n",
-               data->ti_thermal->polling_delay);
-
-       return 0;
-}
-
-/* Get trip type callback functions for thermal zone */
-static int ti_thermal_get_trip_type(struct thermal_zone_device *thermal,
-                                   int trip, enum thermal_trip_type *type)
-{
-       if (!ti_thermal_is_valid_trip(trip))
-               return -EINVAL;
-
-       if (trip + 1 == OMAP_TRIP_NUMBER)
-               *type = THERMAL_TRIP_CRITICAL;
-       else
-               *type = THERMAL_TRIP_PASSIVE;
-
-       return 0;
-}
-
-/* Get trip temperature callback functions for thermal zone */
-static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal,
-                                   int trip, unsigned long *temp)
-{
-       if (!ti_thermal_is_valid_trip(trip))
-               return -EINVAL;
-
-       *temp = ti_thermal_get_trip_value(trip);
-
-       return 0;
-}
-
-/* Get the temperature trend callback functions for thermal zone */
-static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
-                               int trip, enum thermal_trend *trend)
-{
-       struct ti_thermal_data *data = thermal->devdata;
-       struct ti_bandgap *bgp;
-       int id, tr, ret = 0;
-
-       bgp = data->bgp;
-       id = data->sensor_id;
-
-       ret = ti_bandgap_get_trend(bgp, id, &tr);
-       if (ret)
-               return ret;
-
-       if (tr > 0)
-               *trend = THERMAL_TREND_RAISING;
-       else if (tr < 0)
-               *trend = THERMAL_TREND_DROPPING;
-       else
-               *trend = THERMAL_TREND_STABLE;
-
-       return 0;
-}
-
-/* Get critical temperature callback functions for thermal zone */
-static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal,
-                                   unsigned long *temp)
-{
-       /* shutdown zone */
-       return ti_thermal_get_trip_temp(thermal, OMAP_TRIP_NUMBER - 1, temp);
-}
-
-static struct thermal_zone_device_ops ti_thermal_ops = {
-       .get_temp = ti_thermal_get_temp,
-       .get_trend = ti_thermal_get_trend,
-       .bind = ti_thermal_bind,
-       .unbind = ti_thermal_unbind,
-       .get_mode = ti_thermal_get_mode,
-       .set_mode = ti_thermal_set_mode,
-       .get_trip_type = ti_thermal_get_trip_type,
-       .get_trip_temp = ti_thermal_get_trip_temp,
-       .get_crit_temp = ti_thermal_get_crit_temp,
-};
-
-static struct ti_thermal_data
-*ti_thermal_build_data(struct ti_bandgap *bgp, int id)
-{
-       struct ti_thermal_data *data;
-
-       data = devm_kzalloc(bgp->dev, sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               dev_err(bgp->dev, "kzalloc fail\n");
-               return NULL;
-       }
-       data->sensor_id = id;
-       data->bgp = bgp;
-       data->mode = THERMAL_DEVICE_ENABLED;
-       data->pcb_tz = thermal_zone_get_zone_by_name("pcb");
-       INIT_WORK(&data->thermal_wq, ti_thermal_work);
-
-       return data;
-}
-
-int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
-                            char *domain)
-{
-       struct ti_thermal_data *data;
-
-       data = ti_bandgap_get_sensor_data(bgp, id);
-
-       if (IS_ERR_OR_NULL(data))
-               data = ti_thermal_build_data(bgp, id);
-
-       if (!data)
-               return -EINVAL;
-
-       /* Create thermal zone */
-       data->ti_thermal = thermal_zone_device_register(domain,
-                               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)) {
-               dev_err(bgp->dev, "thermal zone device is NULL\n");
-               return PTR_ERR(data->ti_thermal);
-       }
-       data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
-       ti_bandgap_set_sensor_data(bgp, id, data);
-
-       return 0;
-}
-
-int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id)
-{
-       struct ti_thermal_data *data;
-
-       data = ti_bandgap_get_sensor_data(bgp, id);
-
-       thermal_zone_device_unregister(data->ti_thermal);
-
-       return 0;
-}
-
-int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id)
-{
-       struct ti_thermal_data *data;
-
-       data = ti_bandgap_get_sensor_data(bgp, id);
-
-       schedule_work(&data->thermal_wq);
-
-       return 0;
-}
-
-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))
-               data = ti_thermal_build_data(bgp, id);
-
-       if (!data)
-               return -EINVAL;
-
-       if (!cpufreq_get_current_driver()) {
-               dev_dbg(bgp->dev, "no cpufreq driver yet\n");
-               return -EPROBE_DEFER;
-       }
-
-       /* Register cooling device */
-       data->cool_dev = cpufreq_cooling_register(cpu_present_mask);
-       if (IS_ERR_OR_NULL(data->cool_dev)) {
-               dev_err(bgp->dev,
-                       "Failed to register cpufreq cooling device\n");
-               return PTR_ERR(data->cool_dev);
-       }
-       ti_bandgap_set_sensor_data(bgp, id, data);
-
-       return 0;
-}
-
-int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
-{
-       struct ti_thermal_data *data;
-
-       data = ti_bandgap_get_sensor_data(bgp, id);
-       cpufreq_cooling_unregister(data->cool_dev);
-
-       return 0;
-}
diff --git a/drivers/staging/ti-soc-thermal/ti-thermal.h b/drivers/staging/ti-soc-thermal/ti-thermal.h
deleted file mode 100644 (file)
index 5055777..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * OMAP thermal definitions
- *
- * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
- * Contact:
- *   Eduardo Valentin <eduardo.valentin@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-#ifndef __TI_THERMAL_H
-#define __TI_THERMAL_H
-
-#include "ti-bandgap.h"
-
-/* sensors gradient and offsets */
-#define OMAP_GRADIENT_SLOPE_4430                               0
-#define OMAP_GRADIENT_CONST_4430                               20000
-#define OMAP_GRADIENT_SLOPE_4460                               348
-#define OMAP_GRADIENT_CONST_4460                               -9301
-#define OMAP_GRADIENT_SLOPE_4470                               308
-#define OMAP_GRADIENT_CONST_4470                               -7896
-
-#define OMAP_GRADIENT_SLOPE_5430_CPU                           65
-#define OMAP_GRADIENT_CONST_5430_CPU                           -1791
-#define OMAP_GRADIENT_SLOPE_5430_GPU                           117
-#define OMAP_GRADIENT_CONST_5430_GPU                           -2992
-
-/* PCB sensor calculation constants */
-#define OMAP_GRADIENT_SLOPE_W_PCB_4430                         0
-#define OMAP_GRADIENT_CONST_W_PCB_4430                         20000
-#define OMAP_GRADIENT_SLOPE_W_PCB_4460                         1142
-#define OMAP_GRADIENT_CONST_W_PCB_4460                         -393
-#define OMAP_GRADIENT_SLOPE_W_PCB_4470                         1063
-#define OMAP_GRADIENT_CONST_W_PCB_4470                         -477
-
-#define OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU                     100
-#define OMAP_GRADIENT_CONST_W_PCB_5430_CPU                     484
-#define OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU                     464
-#define OMAP_GRADIENT_CONST_W_PCB_5430_GPU                     -5102
-
-/* trip points of interest in milicelsius (at hotspot level) */
-#define OMAP_TRIP_COLD                                         100000
-#define OMAP_TRIP_HOT                                          110000
-#define OMAP_TRIP_SHUTDOWN                                     125000
-#define OMAP_TRIP_NUMBER                                       2
-#define OMAP_TRIP_STEP                                                 \
-       ((OMAP_TRIP_SHUTDOWN - OMAP_TRIP_HOT) / (OMAP_TRIP_NUMBER - 1))
-
-/* Update rates */
-#define FAST_TEMP_MONITORING_RATE                              250
-
-/* helper macros */
-/**
- * ti_thermal_get_trip_value - returns trip temperature based on index
- * @i: trip index
- */
-#define ti_thermal_get_trip_value(i)                                   \
-       (OMAP_TRIP_HOT + ((i) * OMAP_TRIP_STEP))
-
-/**
- * ti_thermal_is_valid_trip - check for trip index
- * @i: trip index
- */
-#define ti_thermal_is_valid_trip(trip)                         \
-       ((trip) >= 0 && (trip) < OMAP_TRIP_NUMBER)
-
-#ifdef CONFIG_TI_THERMAL
-int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, char *domain);
-int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id);
-int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id);
-int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id);
-int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id);
-#else
-static inline
-int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, char *domain)
-{
-       return 0;
-}
-
-static inline
-int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id)
-{
-       return 0;
-}
-
-static inline
-int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id)
-{
-       return 0;
-}
-
-static inline
-int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
-{
-       return 0;
-}
-
-static inline
-int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
-{
-       return 0;
-}
-#endif
-#endif
diff --git a/drivers/staging/ti-soc-thermal/ti_soc_thermal.txt b/drivers/staging/ti-soc-thermal/ti_soc_thermal.txt
deleted file mode 100644 (file)
index 1629652..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-* Texas Instrument OMAP SCM bandgap bindings
-
-In the System Control Module, OMAP supplies a voltage reference
-and a temperature sensor feature that are gathered in the band
-gap voltage and temperature sensor (VBGAPTS) module. The band
-gap provides current and voltage reference for its internal
-circuits and other analog IP blocks. The analog-to-digital
-converter (ADC) produces an output value that is proportional
-to the silicon temperature.
-
-Required properties:
-- compatible : Should be:
-  - "ti,omap4430-bandgap" : for OMAP4430 bandgap
-  - "ti,omap4460-bandgap" : for OMAP4460 bandgap
-  - "ti,omap4470-bandgap" : for OMAP4470 bandgap
-  - "ti,omap5430-bandgap" : for OMAP5430 bandgap
-- 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;
-- 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.
-
-Example:
-OMAP4430:
-bandgap {
-       reg = <0x4a002260 0x4 0x4a00232C 0x4>;
-       compatible = "ti,omap4430-bandgap";
-};
-
-OMAP4460:
-bandgap {
-       reg = <0x4a002260 0x4
-               0x4a00232C 0x4
-               0x4a002378 0x18>;
-       compatible = "ti,omap4460-bandgap";
-       interrupts = <0 126 4>; /* talert */
-       ti,tshut-gpio = <86>;
-};
-
-OMAP4470:
-bandgap {
-       reg = <0x4a002260 0x4
-               0x4a00232C 0x4
-               0x4a002378 0x18>;
-       compatible = "ti,omap4470-bandgap";
-       interrupts = <0 126 4>; /* talert */
-       ti,tshut-gpio = <86>;
-};
-
-OMAP5430:
-bandgap {
-       reg = <0x4a0021e0 0xc
-               0x4a00232c 0xc
-               0x4a002380 0x2c
-               0x4a0023C0 0x3c>;
-       compatible = "ti,omap5430-bandgap";
-       interrupts = <0 126 4>; /* talert */
-};
index d7705e5824fb2d39205d55846d560df2a8a03270..f73da43cdf9e9cfc625e6c8a1a0eaecbc183aedd 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 a0050b2f294ea9248dd5a001805d60834ca5172b..2c437cb8ca00eedfd05f6ff8747f42acc5195375 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 8d8b3ff68490be34fd78382f256bdd5dedda87f2..bbfd28893164e612c672823f97191eaa34c10bb7 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 60ec4b92be034f502216dd5e8d14de4e9c4f6c43..4f77a78edef9dbfc26f218ca3e6147e986a5ebc8 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 dcb199da06b9678d8dbd5fd1446dc0493edae003..08bd87833321c09b14938c210b14e76d2f24a618 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 40d9dbca987b25a811ca0fb75c9c0277f65933a8..586c268679a450aa9b382d9d42b23ca5dfe0cf35 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 cd5018ff9cd78e2b8d547a559e5d0eebb8ff8283..c4675b4ceb494ca5f5ec62c6297d48cfcdf627bc 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 e38222191a33b7c19ef71e827a6d995f31dc8271..35fd6439eb010d08d84c2529416005f4e69950d0 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 08a3bacef0c599ee72ba13e04d28a0c765783a97..1df06d5e4e01ee29353801a671b43d62bf934fbf 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 a4422659d04944f58c85670bfd08c646c1bcf5ff..e4fc34a02f57b0d7ed88354a315efa87f41ed500 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 7c908141cc8a7980d29f151960369c063e06a122..568ad25f25d3d328b901ac3357b0a5bff8eb2115 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 d3536f57444fb7a51bd5313f157e85493d19d6de..e51b09a04d52ec3a50cd34c95f20ffa82a37f716 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 4a8bd36d39588b24d8de02f495e4ca166c022795..e4d22933efaf8ce38a3de9aee51df9d3027c4f6a 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 4630481b60438db290caf48ed8fc60c7f224938c..8f4142fe5f19fdd336bf55bfc761f100ae67ce2c 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 04c775cb3e65ec9a3905d19c34dfea33f28c5705..eb56eb1295635848f9577c2c4872f9cfab656324 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 3240f2cc81efe0b65d2369c5cdadd9d3d22d3df4..bd78faf67c6b366657d572b8e8d1461af77abfec 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 b4a004247ab298a6123c0da08c3d588e5a8e0114..ed75cdd32cb0964f64d1423f29dfb47e3bd3229c 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 0921a64b555028997691fb28ad7ab84294b10a0d..51127d15d5c5accd6e39a8c408ef35a0f521db2f 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 bbc5b0ee2bdc5bb1d2c7d45ea370d8834cbfbed2..8a462773d0c84cec3ae46f1006d75e12dec75279 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 d0b4dd95b91e96628999a362b409543caee5578f..0d7cacb911078929ae99d94abbb249e0c7c699b5 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 21e315874a5472503dfe1ba010dea1236993b553..7172d005d063439999ddaa619ef0a96877b42cec 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 eea69358ced3a5c8eec138eb403b2347905c801e..0dd54a44abcf4da28a4dd560de57043f7bc91ff8 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 b406f178ff390663951ff4915824b67acdfe31b2..0e5a1caed176878d82063a639d81b58e1bceecd2 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 5e3c02554d99574f7fb8d62b130235789b1ab66d..e988c81d763c7d4e3d96c32a9834bcb54a63ee25 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 c054d410ac3f001e7192f63c0bf65767d55b22b3..67184a293e3f615524225c166ec5b2ee2d00d831 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 54ffd64ca3f7560a3b9563bf4087c949a32cf2c6..5e53212b984fd183f329a0fb7f7b48e778199f12 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 c94bf2e5de629419c8e00e29f2cf23ac4507c365..82e15dbb3ac7a1b3b9063a1577c61f3b1025fb27 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 a088d1365ca5ef287e46db053ba3625b8c536473..828f5e345c303ef9b15662477dfd01d16c8a96f6 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 4cbe3eea6debd05989393d7b99fdb385594cec2d..9af4b93c9f866659ac8c584116c92f1bd7b999c6 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 dfeceaffbc03c3f462170d721124ad3b3eac1db9..3b034a0dfc9426ad48018699772fc024163156b6 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 8d7edd4c82285f2bce93fd811b013bb4f6a9a54a..88f92e1a99440c7bb3763ff691e3d01d09e2ad25 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 3c5ee5607977c562dca9209d44c1b2627a2b760f..ab79ea4701d9f88df85b693c41f96a7d80faaea8 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 d755440791b7ce0a01d3e186e423ed6769fcc8be..1f02e8edb45c9f6b36dae08a563b47efecf4c99d 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);
diff --git a/drivers/thermal/ti-soc-thermal/Kconfig b/drivers/thermal/ti-soc-thermal/Kconfig
new file mode 100644 (file)
index 0000000..bd4c7be
--- /dev/null
@@ -0,0 +1,60 @@
+config TI_SOC_THERMAL
+       tristate "Texas Instruments SoCs temperature sensor driver"
+       depends on THERMAL
+       depends on ARCH_HAS_BANDGAP
+       help
+         If you say yes here you get support for the Texas Instruments
+         OMAP4460+ on die bandgap temperature sensor support. The register
+         set is part of system control module.
+
+         This includes alert interrupts generation and also the TSHUT
+         support.
+
+config TI_THERMAL
+       bool "Texas Instruments SoCs thermal framework support"
+       depends on TI_SOC_THERMAL
+       depends on CPU_THERMAL
+       help
+         If you say yes here you want to get support for generic thermal
+         framework for the Texas Instruments on die bandgap temperature sensor.
+
+         This includes trip points definitions, extrapolation rules and
+         CPU cooling device bindings.
+
+config OMAP4_THERMAL
+       bool "Texas Instruments OMAP4 thermal support"
+       depends on TI_SOC_THERMAL
+       depends on ARCH_OMAP4
+       help
+         If you say yes here you get thermal support for the Texas Instruments
+         OMAP4 SoC family. The current chip supported are:
+          - OMAP4430
+          - OMAP4460
+          - OMAP4470
+
+         This includes alert interrupts generation and also the TSHUT
+         support.
+
+config OMAP5_THERMAL
+       bool "Texas Instruments OMAP5 thermal support"
+       depends on TI_SOC_THERMAL
+       depends on SOC_OMAP5
+       help
+         If you say yes here you get thermal support for the Texas Instruments
+         OMAP5 SoC family. The current chip supported are:
+          - OMAP5430
+
+         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.
diff --git a/drivers/thermal/ti-soc-thermal/Makefile b/drivers/thermal/ti-soc-thermal/Makefile
new file mode 100644 (file)
index 0000000..1226b24
--- /dev/null
@@ -0,0 +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/TODO b/drivers/thermal/ti-soc-thermal/TODO
new file mode 100644 (file)
index 0000000..7da787d
--- /dev/null
@@ -0,0 +1,12 @@
+List of TODOs (by Eduardo Valentin)
+
+on ti-bandgap.c:
+- Revisit PM support
+
+on ti-thermal-common.c/ti-thermal.h:
+- Revisit need for locking
+
+generally:
+- make sure this code works on OMAP4430, OMAP4460 and OMAP5430
+
+Copy patches to Eduardo Valentin <eduardo.valentin@ti.com>
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,
+};
diff --git a/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c
new file mode 100644 (file)
index 0000000..d255d33
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * OMAP4 thermal driver.
+ *
+ * Copyright (C) 2011-2012 Texas Instruments Inc.
+ * Contact:
+ *     Eduardo Valentin <eduardo.valentin@ti.com>
+ *
+ * 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 "omap4xxx-bandgap.h"
+
+/*
+ * OMAP4430 has one instance of thermal sensor for MPU
+ * need to describe the individual bit fields
+ */
+static struct temp_sensor_registers
+omap4430_mpu_temp_sensor_registers = {
+       .temp_sensor_ctrl = OMAP4430_TEMP_SENSOR_CTRL_OFFSET,
+       .bgap_tempsoff_mask = OMAP4430_BGAP_TEMPSOFF_MASK,
+       .bgap_soc_mask = OMAP4430_BGAP_TEMP_SENSOR_SOC_MASK,
+       .bgap_eocz_mask = OMAP4430_BGAP_TEMP_SENSOR_EOCZ_MASK,
+       .bgap_dtemp_mask = OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK,
+
+       .bgap_mode_ctrl = OMAP4430_TEMP_SENSOR_CTRL_OFFSET,
+       .mode_ctrl_mask = OMAP4430_SINGLE_MODE_MASK,
+
+       .bgap_efuse = OMAP4430_FUSE_OPP_BGAP,
+};
+
+/* Thresholds and limits for OMAP4430 MPU temperature sensor */
+static struct temp_sensor_data omap4430_mpu_temp_sensor_data = {
+       .min_freq = OMAP4430_MIN_FREQ,
+       .max_freq = OMAP4430_MAX_FREQ,
+       .max_temp = OMAP4430_MAX_TEMP,
+       .min_temp = OMAP4430_MIN_TEMP,
+       .hyst_val = OMAP4430_HYST_VAL,
+};
+
+/*
+ * Temperature values in milli degree celsius
+ * ADC code values from 530 to 923
+ */
+static const int
+omap4430_adc_to_temp[OMAP4430_ADC_END_VALUE - OMAP4430_ADC_START_VALUE + 1] = {
+       -38000, -35000, -34000, -32000, -30000, -28000, -26000, -24000, -22000,
+       -20000, -18000, -17000, -15000, -13000, -12000, -10000, -8000, -6000,
+       -5000, -3000, -1000, 0, 2000, 3000, 5000, 6000, 8000, 10000, 12000,
+       13000, 15000, 17000, 19000, 21000, 23000, 25000, 27000, 28000, 30000,
+       32000, 33000, 35000, 37000, 38000, 40000, 42000, 43000, 45000, 47000,
+       48000, 50000, 52000, 53000, 55000, 57000, 58000, 60000, 62000, 64000,
+       66000, 68000, 70000, 71000, 73000, 75000, 77000, 78000, 80000, 82000,
+       83000, 85000, 87000, 88000, 90000, 92000, 93000, 95000, 97000, 98000,
+       100000, 102000, 103000, 105000, 107000, 109000, 111000, 113000, 115000,
+       117000, 118000, 120000, 122000, 123000,
+};
+
+/* OMAP4430 data */
+const struct ti_bandgap_data omap4430_data = {
+       .features = TI_BANDGAP_FEATURE_MODE_CONFIG |
+                       TI_BANDGAP_FEATURE_CLK_CTRL |
+                       TI_BANDGAP_FEATURE_POWER_SWITCH,
+       .fclock_name = "bandgap_fclk",
+       .div_ck_name = "bandgap_fclk",
+       .conv_table = omap4430_adc_to_temp,
+       .adc_start_val = OMAP4430_ADC_START_VALUE,
+       .adc_end_val = OMAP4430_ADC_END_VALUE,
+       .expose_sensor = ti_thermal_expose_sensor,
+       .remove_sensor = ti_thermal_remove_sensor,
+       .sensors = {
+               {
+               .registers = &omap4430_mpu_temp_sensor_registers,
+               .ts_data = &omap4430_mpu_temp_sensor_data,
+               .domain = "cpu",
+               .slope = OMAP_GRADIENT_SLOPE_4430,
+               .constant = OMAP_GRADIENT_CONST_4430,
+               .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4430,
+               .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4430,
+               .register_cooling = ti_thermal_register_cpu_cooling,
+               .unregister_cooling = ti_thermal_unregister_cpu_cooling,
+               },
+       },
+       .sensor_count = 1,
+};
+/*
+ * OMAP4460 has one instance of thermal sensor for MPU
+ * need to describe the individual bit fields
+ */
+static struct temp_sensor_registers
+omap4460_mpu_temp_sensor_registers = {
+       .temp_sensor_ctrl = OMAP4460_TEMP_SENSOR_CTRL_OFFSET,
+       .bgap_tempsoff_mask = OMAP4460_BGAP_TEMPSOFF_MASK,
+       .bgap_soc_mask = OMAP4460_BGAP_TEMP_SENSOR_SOC_MASK,
+       .bgap_eocz_mask = OMAP4460_BGAP_TEMP_SENSOR_EOCZ_MASK,
+       .bgap_dtemp_mask = OMAP4460_BGAP_TEMP_SENSOR_DTEMP_MASK,
+
+       .bgap_mask_ctrl = OMAP4460_BGAP_CTRL_OFFSET,
+       .mask_hot_mask = OMAP4460_MASK_HOT_MASK,
+       .mask_cold_mask = OMAP4460_MASK_COLD_MASK,
+
+       .bgap_mode_ctrl = OMAP4460_BGAP_CTRL_OFFSET,
+       .mode_ctrl_mask = OMAP4460_SINGLE_MODE_MASK,
+
+       .bgap_counter = OMAP4460_BGAP_COUNTER_OFFSET,
+       .counter_mask = OMAP4460_COUNTER_MASK,
+
+       .bgap_threshold = OMAP4460_BGAP_THRESHOLD_OFFSET,
+       .threshold_thot_mask = OMAP4460_T_HOT_MASK,
+       .threshold_tcold_mask = OMAP4460_T_COLD_MASK,
+
+       .tshut_threshold = OMAP4460_BGAP_TSHUT_OFFSET,
+       .tshut_hot_mask = OMAP4460_TSHUT_HOT_MASK,
+       .tshut_cold_mask = OMAP4460_TSHUT_COLD_MASK,
+
+       .bgap_status = OMAP4460_BGAP_STATUS_OFFSET,
+       .status_clean_stop_mask = OMAP4460_CLEAN_STOP_MASK,
+       .status_bgap_alert_mask = OMAP4460_BGAP_ALERT_MASK,
+       .status_hot_mask = OMAP4460_HOT_FLAG_MASK,
+       .status_cold_mask = OMAP4460_COLD_FLAG_MASK,
+
+       .bgap_efuse = OMAP4460_FUSE_OPP_BGAP,
+};
+
+/* Thresholds and limits for OMAP4460 MPU temperature sensor */
+static struct temp_sensor_data omap4460_mpu_temp_sensor_data = {
+       .tshut_hot = OMAP4460_TSHUT_HOT,
+       .tshut_cold = OMAP4460_TSHUT_COLD,
+       .t_hot = OMAP4460_T_HOT,
+       .t_cold = OMAP4460_T_COLD,
+       .min_freq = OMAP4460_MIN_FREQ,
+       .max_freq = OMAP4460_MAX_FREQ,
+       .max_temp = OMAP4460_MAX_TEMP,
+       .min_temp = OMAP4460_MIN_TEMP,
+       .hyst_val = OMAP4460_HYST_VAL,
+       .update_int1 = 1000,
+       .update_int2 = 2000,
+};
+
+/*
+ * Temperature values in milli degree celsius
+ * ADC code values from 530 to 923
+ */
+static const int
+omap4460_adc_to_temp[OMAP4460_ADC_END_VALUE - OMAP4460_ADC_START_VALUE + 1] = {
+       -40000, -40000, -40000, -40000, -39800, -39400, -39000, -38600, -38200,
+       -37800, -37300, -36800, -36400, -36000, -35600, -35200, -34800,
+       -34300, -33800, -33400, -33000, -32600, -32200, -31800, -31300,
+       -30800, -30400, -30000, -29600, -29200, -28700, -28200, -27800,
+       -27400, -27000, -26600, -26200, -25700, -25200, -24800, -24400,
+       -24000, -23600, -23200, -22700, -22200, -21800, -21400, -21000,
+       -20600, -20200, -19700, -19200, -18800, -18400, -18000, -17600,
+       -17200, -16700, -16200, -15800, -15400, -15000, -14600, -14200,
+       -13700, -13200, -12800, -12400, -12000, -11600, -11200, -10700,
+       -10200, -9800, -9400, -9000, -8600, -8200, -7700, -7200, -6800,
+       -6400, -6000, -5600, -5200, -4800, -4300, -3800, -3400, -3000,
+       -2600, -2200, -1800, -1300, -800, -400, 0, 400, 800, 1200, 1600,
+       2100, 2600, 3000, 3400, 3800, 4200, 4600, 5100, 5600, 6000, 6400,
+       6800, 7200, 7600, 8000, 8500, 9000, 9400, 9800, 10200, 10600, 11000,
+       11400, 11900, 12400, 12800, 13200, 13600, 14000, 14400, 14800,
+       15300, 15800, 16200, 16600, 17000, 17400, 17800, 18200, 18700,
+       19200, 19600, 20000, 20400, 20800, 21200, 21600, 22100, 22600,
+       23000, 23400, 23800, 24200, 24600, 25000, 25400, 25900, 26400,
+       26800, 27200, 27600, 28000, 28400, 28800, 29300, 29800, 30200,
+       30600, 31000, 31400, 31800, 32200, 32600, 33100, 33600, 34000,
+       34400, 34800, 35200, 35600, 36000, 36400, 36800, 37300, 37800,
+       38200, 38600, 39000, 39400, 39800, 40200, 40600, 41100, 41600,
+       42000, 42400, 42800, 43200, 43600, 44000, 44400, 44800, 45300,
+       45800, 46200, 46600, 47000, 47400, 47800, 48200, 48600, 49000,
+       49500, 50000, 50400, 50800, 51200, 51600, 52000, 52400, 52800,
+       53200, 53700, 54200, 54600, 55000, 55400, 55800, 56200, 56600,
+       57000, 57400, 57800, 58200, 58700, 59200, 59600, 60000, 60400,
+       60800, 61200, 61600, 62000, 62400, 62800, 63300, 63800, 64200,
+       64600, 65000, 65400, 65800, 66200, 66600, 67000, 67400, 67800,
+       68200, 68700, 69200, 69600, 70000, 70400, 70800, 71200, 71600,
+       72000, 72400, 72800, 73200, 73600, 74100, 74600, 75000, 75400,
+       75800, 76200, 76600, 77000, 77400, 77800, 78200, 78600, 79000,
+       79400, 79800, 80300, 80800, 81200, 81600, 82000, 82400, 82800,
+       83200, 83600, 84000, 84400, 84800, 85200, 85600, 86000, 86400,
+       86800, 87300, 87800, 88200, 88600, 89000, 89400, 89800, 90200,
+       90600, 91000, 91400, 91800, 92200, 92600, 93000, 93400, 93800,
+       94200, 94600, 95000, 95500, 96000, 96400, 96800, 97200, 97600,
+       98000, 98400, 98800, 99200, 99600, 100000, 100400, 100800, 101200,
+       101600, 102000, 102400, 102800, 103200, 103600, 104000, 104400,
+       104800, 105200, 105600, 106100, 106600, 107000, 107400, 107800,
+       108200, 108600, 109000, 109400, 109800, 110200, 110600, 111000,
+       111400, 111800, 112200, 112600, 113000, 113400, 113800, 114200,
+       114600, 115000, 115400, 115800, 116200, 116600, 117000, 117400,
+       117800, 118200, 118600, 119000, 119400, 119800, 120200, 120600,
+       121000, 121400, 121800, 122200, 122600, 123000, 123400, 123800, 124200,
+       124600, 124900, 125000, 125000, 125000, 125000
+};
+
+/* OMAP4460 data */
+const struct ti_bandgap_data omap4460_data = {
+       .features = TI_BANDGAP_FEATURE_TSHUT |
+                       TI_BANDGAP_FEATURE_TSHUT_CONFIG |
+                       TI_BANDGAP_FEATURE_TALERT |
+                       TI_BANDGAP_FEATURE_MODE_CONFIG |
+                       TI_BANDGAP_FEATURE_POWER_SWITCH |
+                       TI_BANDGAP_FEATURE_CLK_CTRL |
+                       TI_BANDGAP_FEATURE_COUNTER,
+       .fclock_name = "bandgap_ts_fclk",
+       .div_ck_name = "div_ts_ck",
+       .conv_table = omap4460_adc_to_temp,
+       .adc_start_val = OMAP4460_ADC_START_VALUE,
+       .adc_end_val = OMAP4460_ADC_END_VALUE,
+       .expose_sensor = ti_thermal_expose_sensor,
+       .remove_sensor = ti_thermal_remove_sensor,
+       .report_temperature = ti_thermal_report_sensor_temperature,
+       .sensors = {
+               {
+               .registers = &omap4460_mpu_temp_sensor_registers,
+               .ts_data = &omap4460_mpu_temp_sensor_data,
+               .domain = "cpu",
+               .slope = OMAP_GRADIENT_SLOPE_4460,
+               .constant = OMAP_GRADIENT_CONST_4460,
+               .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4460,
+               .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4460,
+               .register_cooling = ti_thermal_register_cpu_cooling,
+               .unregister_cooling = ti_thermal_unregister_cpu_cooling,
+               },
+       },
+       .sensor_count = 1,
+};
+
+/* OMAP4470 data */
+const struct ti_bandgap_data omap4470_data = {
+       .features = TI_BANDGAP_FEATURE_TSHUT |
+                       TI_BANDGAP_FEATURE_TSHUT_CONFIG |
+                       TI_BANDGAP_FEATURE_TALERT |
+                       TI_BANDGAP_FEATURE_MODE_CONFIG |
+                       TI_BANDGAP_FEATURE_POWER_SWITCH |
+                       TI_BANDGAP_FEATURE_CLK_CTRL |
+                       TI_BANDGAP_FEATURE_COUNTER,
+       .fclock_name = "bandgap_ts_fclk",
+       .div_ck_name = "div_ts_ck",
+       .conv_table = omap4460_adc_to_temp,
+       .adc_start_val = OMAP4460_ADC_START_VALUE,
+       .adc_end_val = OMAP4460_ADC_END_VALUE,
+       .expose_sensor = ti_thermal_expose_sensor,
+       .remove_sensor = ti_thermal_remove_sensor,
+       .report_temperature = ti_thermal_report_sensor_temperature,
+       .sensors = {
+               {
+               .registers = &omap4460_mpu_temp_sensor_registers,
+               .ts_data = &omap4460_mpu_temp_sensor_data,
+               .domain = "cpu",
+               .slope = OMAP_GRADIENT_SLOPE_4470,
+               .constant = OMAP_GRADIENT_CONST_4470,
+               .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4470,
+               .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4470,
+               .register_cooling = ti_thermal_register_cpu_cooling,
+               .unregister_cooling = ti_thermal_unregister_cpu_cooling,
+               },
+       },
+       .sensor_count = 1,
+};
diff --git a/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h b/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h
new file mode 100644 (file)
index 0000000..6f2de3a
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * OMAP4xxx bandgap registers, bitfields and temperature definitions
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
+ * Contact:
+ *   Eduardo Valentin <eduardo.valentin@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef __OMAP4XXX_BANDGAP_H
+#define __OMAP4XXX_BANDGAP_H
+
+/**
+ * *** OMAP4430 ***
+ *
+ * Below, in sequence, are the Register definitions,
+ * the bitfields and the temperature definitions for OMAP4430.
+ */
+
+/**
+ * OMAP4430 register definitions
+ *
+ * Registers are defined as offsets. The offsets are
+ * relative to FUSE_OPP_BGAP on 4430.
+ */
+
+/* OMAP4430.FUSE_OPP_BGAP */
+#define OMAP4430_FUSE_OPP_BGAP                         0x0
+
+/* OMAP4430.TEMP_SENSOR  */
+#define OMAP4430_TEMP_SENSOR_CTRL_OFFSET               0xCC
+
+/**
+ * Register and bit definitions for OMAP4430
+ *
+ * All the macros bellow define the required bits for
+ * controlling temperature on OMAP4430. Bit defines are
+ * grouped by register.
+ */
+
+/* OMAP4430.TEMP_SENSOR bits */
+#define OMAP4430_BGAP_TEMPSOFF_MASK                    BIT(12)
+#define OMAP4430_BGAP_TSHUT_MASK                       BIT(11)
+#define OMAP4430_SINGLE_MODE_MASK                      BIT(10)
+#define OMAP4430_BGAP_TEMP_SENSOR_SOC_MASK             BIT(9)
+#define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_MASK            BIT(8)
+#define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK           (0xff << 0)
+
+/**
+ * Temperature limits and thresholds for OMAP4430
+ *
+ * All the macros bellow are definitions for handling the
+ * ADC conversions and representation of temperature limits
+ * and thresholds for OMAP4430.
+ */
+
+/* ADC conversion table limits */
+#define OMAP4430_ADC_START_VALUE                       0
+#define OMAP4430_ADC_END_VALUE                         127
+/* bandgap clock limits (no control on 4430) */
+#define OMAP4430_MAX_FREQ                              32768
+#define OMAP4430_MIN_FREQ                              32768
+/* sensor limits */
+#define OMAP4430_MIN_TEMP                              -40000
+#define OMAP4430_MAX_TEMP                              125000
+#define OMAP4430_HYST_VAL                              5000
+
+/**
+ * *** OMAP4460 *** Applicable for OMAP4470
+ *
+ * Below, in sequence, are the Register definitions,
+ * the bitfields and the temperature definitions for OMAP4460.
+ */
+
+/**
+ * OMAP4460 register definitions
+ *
+ * Registers are defined as offsets. The offsets are
+ * relative to FUSE_OPP_BGAP on 4460.
+ */
+
+/* OMAP4460.FUSE_OPP_BGAP */
+#define OMAP4460_FUSE_OPP_BGAP                         0x0
+
+/* OMAP4460.TEMP_SENSOR */
+#define OMAP4460_TEMP_SENSOR_CTRL_OFFSET               0xCC
+
+/* OMAP4460.BANDGAP_CTRL */
+#define OMAP4460_BGAP_CTRL_OFFSET                      0x118
+
+/* OMAP4460.BANDGAP_COUNTER */
+#define OMAP4460_BGAP_COUNTER_OFFSET                   0x11C
+
+/* OMAP4460.BANDGAP_THRESHOLD */
+#define OMAP4460_BGAP_THRESHOLD_OFFSET                 0x120
+
+/* OMAP4460.TSHUT_THRESHOLD */
+#define OMAP4460_BGAP_TSHUT_OFFSET                     0x124
+
+/* OMAP4460.BANDGAP_STATUS */
+#define OMAP4460_BGAP_STATUS_OFFSET                    0x128
+
+/**
+ * Register bitfields for OMAP4460
+ *
+ * All the macros bellow define the required bits for
+ * controlling temperature on OMAP4460. Bit defines are
+ * grouped by register.
+ */
+/* OMAP4460.TEMP_SENSOR bits */
+#define OMAP4460_BGAP_TEMPSOFF_MASK                    BIT(13)
+#define OMAP4460_BGAP_TEMP_SENSOR_SOC_MASK             BIT(11)
+#define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_MASK            BIT(10)
+#define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_MASK           (0x3ff << 0)
+
+/* OMAP4460.BANDGAP_CTRL bits */
+#define OMAP4460_SINGLE_MODE_MASK                      BIT(31)
+#define OMAP4460_MASK_HOT_MASK                         BIT(1)
+#define OMAP4460_MASK_COLD_MASK                                BIT(0)
+
+/* OMAP4460.BANDGAP_COUNTER bits */
+#define OMAP4460_COUNTER_MASK                          (0xffffff << 0)
+
+/* OMAP4460.BANDGAP_THRESHOLD bits */
+#define OMAP4460_T_HOT_MASK                            (0x3ff << 16)
+#define OMAP4460_T_COLD_MASK                           (0x3ff << 0)
+
+/* OMAP4460.TSHUT_THRESHOLD bits */
+#define OMAP4460_TSHUT_HOT_MASK                                (0x3ff << 16)
+#define OMAP4460_TSHUT_COLD_MASK                       (0x3ff << 0)
+
+/* OMAP4460.BANDGAP_STATUS bits */
+#define OMAP4460_CLEAN_STOP_MASK                       BIT(3)
+#define OMAP4460_BGAP_ALERT_MASK                       BIT(2)
+#define OMAP4460_HOT_FLAG_MASK                         BIT(1)
+#define OMAP4460_COLD_FLAG_MASK                                BIT(0)
+
+/**
+ * Temperature limits and thresholds for OMAP4460
+ *
+ * All the macros bellow are definitions for handling the
+ * ADC conversions and representation of temperature limits
+ * and thresholds for OMAP4460.
+ */
+
+/* ADC conversion table limits */
+#define OMAP4460_ADC_START_VALUE                       530
+#define OMAP4460_ADC_END_VALUE                         932
+/* bandgap clock limits */
+#define OMAP4460_MAX_FREQ                              1500000
+#define OMAP4460_MIN_FREQ                              1000000
+/* sensor limits */
+#define OMAP4460_MIN_TEMP                              -40000
+#define OMAP4460_MAX_TEMP                              123000
+#define OMAP4460_HYST_VAL                              5000
+/* interrupts thresholds */
+#define OMAP4460_TSHUT_HOT                             900     /* 122 deg C */
+#define OMAP4460_TSHUT_COLD                            895     /* 100 deg C */
+#define OMAP4460_T_HOT                                 800     /* 73 deg C */
+#define OMAP4460_T_COLD                                        795     /* 71 deg C */
+
+#endif /* __OMAP4XXX_BANDGAP_H */
diff --git a/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c
new file mode 100644 (file)
index 0000000..eff0c80
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * OMAP5 thermal driver.
+ *
+ * Copyright (C) 2011-2012 Texas Instruments Inc.
+ * Contact:
+ *     Eduardo Valentin <eduardo.valentin@ti.com>
+ *
+ * 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 "omap5xxx-bandgap.h"
+
+/*
+ * OMAP5430 has three instances of thermal sensor for MPU, GPU & CORE,
+ * need to describe the individual registers and bit fields.
+ */
+
+/*
+ * OMAP5430 MPU thermal sensor register offset and bit-fields
+ */
+static struct temp_sensor_registers
+omap5430_mpu_temp_sensor_registers = {
+       .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_MPU_OFFSET,
+       .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
+       .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
+       .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
+
+       .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
+       .mask_hot_mask = OMAP5430_MASK_HOT_MPU_MASK,
+       .mask_cold_mask = OMAP5430_MASK_COLD_MPU_MASK,
+       .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK,
+       .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK,
+       .mask_freeze_mask = OMAP5430_MASK_FREEZE_MPU_MASK,
+       .mask_clear_mask = OMAP5430_MASK_CLEAR_MPU_MASK,
+       .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_MPU_MASK,
+
+
+       .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET,
+       .counter_mask = OMAP5430_COUNTER_MASK,
+
+       .bgap_threshold = OMAP5430_BGAP_THRESHOLD_MPU_OFFSET,
+       .threshold_thot_mask = OMAP5430_T_HOT_MASK,
+       .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
+
+       .tshut_threshold = OMAP5430_BGAP_TSHUT_MPU_OFFSET,
+       .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
+       .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
+
+       .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
+       .status_clean_stop_mask = 0x0,
+       .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
+       .status_hot_mask = OMAP5430_HOT_MPU_FLAG_MASK,
+       .status_cold_mask = OMAP5430_COLD_MPU_FLAG_MASK,
+
+       .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_MPU_OFFSET,
+       .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_MPU_0_OFFSET,
+       .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_MPU_1_OFFSET,
+       .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_MPU_2_OFFSET,
+       .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_MPU_3_OFFSET,
+       .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_MPU_4_OFFSET,
+       .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_MPU,
+};
+
+/*
+ * OMAP5430 GPU thermal sensor register offset and bit-fields
+ */
+static struct temp_sensor_registers
+omap5430_gpu_temp_sensor_registers = {
+       .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_GPU_OFFSET,
+       .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
+       .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
+       .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
+
+       .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
+       .mask_hot_mask = OMAP5430_MASK_HOT_GPU_MASK,
+       .mask_cold_mask = OMAP5430_MASK_COLD_GPU_MASK,
+       .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK,
+       .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK,
+       .mask_freeze_mask = OMAP5430_MASK_FREEZE_GPU_MASK,
+       .mask_clear_mask = OMAP5430_MASK_CLEAR_GPU_MASK,
+       .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_GPU_MASK,
+
+       .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET,
+       .counter_mask = OMAP5430_COUNTER_MASK,
+
+       .bgap_threshold = OMAP5430_BGAP_THRESHOLD_GPU_OFFSET,
+       .threshold_thot_mask = OMAP5430_T_HOT_MASK,
+       .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
+
+       .tshut_threshold = OMAP5430_BGAP_TSHUT_GPU_OFFSET,
+       .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
+       .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
+
+       .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
+       .status_clean_stop_mask = 0x0,
+       .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
+       .status_hot_mask = OMAP5430_HOT_GPU_FLAG_MASK,
+       .status_cold_mask = OMAP5430_COLD_GPU_FLAG_MASK,
+
+       .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_GPU_OFFSET,
+       .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_GPU_0_OFFSET,
+       .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_GPU_1_OFFSET,
+       .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_GPU_2_OFFSET,
+       .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_GPU_3_OFFSET,
+       .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_GPU_4_OFFSET,
+
+       .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_GPU,
+};
+
+/*
+ * OMAP5430 CORE thermal sensor register offset and bit-fields
+ */
+static struct temp_sensor_registers
+omap5430_core_temp_sensor_registers = {
+       .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_CORE_OFFSET,
+       .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
+       .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
+       .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
+
+       .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
+       .mask_hot_mask = OMAP5430_MASK_HOT_CORE_MASK,
+       .mask_cold_mask = OMAP5430_MASK_COLD_CORE_MASK,
+       .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK,
+       .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK,
+       .mask_freeze_mask = OMAP5430_MASK_FREEZE_CORE_MASK,
+       .mask_clear_mask = OMAP5430_MASK_CLEAR_CORE_MASK,
+       .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_CORE_MASK,
+
+       .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET,
+       .counter_mask = OMAP5430_COUNTER_MASK,
+
+       .bgap_threshold = OMAP5430_BGAP_THRESHOLD_CORE_OFFSET,
+       .threshold_thot_mask = OMAP5430_T_HOT_MASK,
+       .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
+
+       .tshut_threshold = OMAP5430_BGAP_TSHUT_CORE_OFFSET,
+       .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
+       .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
+
+       .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
+       .status_clean_stop_mask = 0x0,
+       .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
+       .status_hot_mask = OMAP5430_HOT_CORE_FLAG_MASK,
+       .status_cold_mask = OMAP5430_COLD_CORE_FLAG_MASK,
+
+       .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_CORE_OFFSET,
+       .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_CORE_0_OFFSET,
+       .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_CORE_1_OFFSET,
+       .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_CORE_2_OFFSET,
+       .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_CORE_3_OFFSET,
+       .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_CORE_4_OFFSET,
+
+       .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_CORE,
+};
+
+/* Thresholds and limits for OMAP5430 MPU temperature sensor */
+static struct temp_sensor_data omap5430_mpu_temp_sensor_data = {
+       .tshut_hot = OMAP5430_MPU_TSHUT_HOT,
+       .tshut_cold = OMAP5430_MPU_TSHUT_COLD,
+       .t_hot = OMAP5430_MPU_T_HOT,
+       .t_cold = OMAP5430_MPU_T_COLD,
+       .min_freq = OMAP5430_MPU_MIN_FREQ,
+       .max_freq = OMAP5430_MPU_MAX_FREQ,
+       .max_temp = OMAP5430_MPU_MAX_TEMP,
+       .min_temp = OMAP5430_MPU_MIN_TEMP,
+       .hyst_val = OMAP5430_MPU_HYST_VAL,
+       .update_int1 = 1000,
+       .update_int2 = 2000,
+};
+
+/* Thresholds and limits for OMAP5430 GPU temperature sensor */
+static struct temp_sensor_data omap5430_gpu_temp_sensor_data = {
+       .tshut_hot = OMAP5430_GPU_TSHUT_HOT,
+       .tshut_cold = OMAP5430_GPU_TSHUT_COLD,
+       .t_hot = OMAP5430_GPU_T_HOT,
+       .t_cold = OMAP5430_GPU_T_COLD,
+       .min_freq = OMAP5430_GPU_MIN_FREQ,
+       .max_freq = OMAP5430_GPU_MAX_FREQ,
+       .max_temp = OMAP5430_GPU_MAX_TEMP,
+       .min_temp = OMAP5430_GPU_MIN_TEMP,
+       .hyst_val = OMAP5430_GPU_HYST_VAL,
+       .update_int1 = 1000,
+       .update_int2 = 2000,
+};
+
+/* Thresholds and limits for OMAP5430 CORE temperature sensor */
+static struct temp_sensor_data omap5430_core_temp_sensor_data = {
+       .tshut_hot = OMAP5430_CORE_TSHUT_HOT,
+       .tshut_cold = OMAP5430_CORE_TSHUT_COLD,
+       .t_hot = OMAP5430_CORE_T_HOT,
+       .t_cold = OMAP5430_CORE_T_COLD,
+       .min_freq = OMAP5430_CORE_MIN_FREQ,
+       .max_freq = OMAP5430_CORE_MAX_FREQ,
+       .max_temp = OMAP5430_CORE_MAX_TEMP,
+       .min_temp = OMAP5430_CORE_MIN_TEMP,
+       .hyst_val = OMAP5430_CORE_HYST_VAL,
+       .update_int1 = 1000,
+       .update_int2 = 2000,
+};
+
+/*
+ * OMAP54xx ES2.0 : Temperature values in milli degree celsius
+ * ADC code values from 540 to 945
+ */
+static int
+omap5430_adc_to_temp[
+       OMAP5430_ADC_END_VALUE - OMAP5430_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, -21600, -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, 21100,
+       /* 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, 122400, 122600, 123000,
+       123400,
+       /* Index 940 - 945 */
+       123800, 1242000, 124600, 124900, 125000, 125000,
+};
+
+/* OMAP54xx ES2.0 data */
+const struct ti_bandgap_data omap5430_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 = omap5430_adc_to_temp,
+       .adc_start_val = OMAP5430_ADC_START_VALUE,
+       .adc_end_val = OMAP5430_ADC_END_VALUE,
+       .expose_sensor = ti_thermal_expose_sensor,
+       .remove_sensor = ti_thermal_remove_sensor,
+       .report_temperature = ti_thermal_report_sensor_temperature,
+       .sensors = {
+               {
+               .registers = &omap5430_mpu_temp_sensor_registers,
+               .ts_data = &omap5430_mpu_temp_sensor_data,
+               .domain = "cpu",
+               .register_cooling = ti_thermal_register_cpu_cooling,
+               .unregister_cooling = ti_thermal_unregister_cpu_cooling,
+               .slope = OMAP_GRADIENT_SLOPE_5430_CPU,
+               .constant = OMAP_GRADIENT_CONST_5430_CPU,
+               .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU,
+               .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_CPU,
+               },
+               {
+               .registers = &omap5430_gpu_temp_sensor_registers,
+               .ts_data = &omap5430_gpu_temp_sensor_data,
+               .domain = "gpu",
+               .slope = OMAP_GRADIENT_SLOPE_5430_GPU,
+               .constant = OMAP_GRADIENT_CONST_5430_GPU,
+               .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU,
+               .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_GPU,
+               },
+               {
+               .registers = &omap5430_core_temp_sensor_registers,
+               .ts_data = &omap5430_core_temp_sensor_data,
+               .domain = "core",
+               },
+       },
+       .sensor_count = 3,
+};
diff --git a/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h b/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h
new file mode 100644 (file)
index 0000000..400b55d
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * OMAP5xxx bandgap registers, bitfields and temperature definitions
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
+ * Contact:
+ *   Eduardo Valentin <eduardo.valentin@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef __OMAP5XXX_BANDGAP_H
+#define __OMAP5XXX_BANDGAP_H
+
+/**
+ * *** OMAP5430 ***
+ *
+ * Below, in sequence, are the Register definitions,
+ * the bitfields and the temperature definitions for OMAP5430.
+ */
+
+/**
+ * OMAP5430 register definitions
+ *
+ * Registers are defined as offsets. The offsets are
+ * relative to FUSE_OPP_BGAP_GPU on 5430.
+ *
+ * Register below are grouped by domain (not necessarily in offset order)
+ */
+
+/* OMAP5430.GPU register offsets */
+#define OMAP5430_FUSE_OPP_BGAP_GPU                     0x0
+#define OMAP5430_TEMP_SENSOR_GPU_OFFSET                        0x150
+#define OMAP5430_BGAP_THRESHOLD_GPU_OFFSET             0x1A8
+#define OMAP5430_BGAP_TSHUT_GPU_OFFSET                 0x1B4
+#define OMAP5430_BGAP_CUMUL_DTEMP_GPU_OFFSET           0x1C0
+#define OMAP5430_BGAP_DTEMP_GPU_0_OFFSET               0x1F4
+#define OMAP5430_BGAP_DTEMP_GPU_1_OFFSET               0x1F8
+#define OMAP5430_BGAP_DTEMP_GPU_2_OFFSET               0x1FC
+#define OMAP5430_BGAP_DTEMP_GPU_3_OFFSET               0x200
+#define OMAP5430_BGAP_DTEMP_GPU_4_OFFSET               0x204
+
+/* OMAP5430.MPU register offsets */
+#define OMAP5430_FUSE_OPP_BGAP_MPU                     0x4
+#define OMAP5430_TEMP_SENSOR_MPU_OFFSET                        0x14C
+#define OMAP5430_BGAP_THRESHOLD_MPU_OFFSET             0x1A4
+#define OMAP5430_BGAP_TSHUT_MPU_OFFSET                 0x1B0
+#define OMAP5430_BGAP_CUMUL_DTEMP_MPU_OFFSET           0x1BC
+#define OMAP5430_BGAP_DTEMP_MPU_0_OFFSET               0x1E0
+#define OMAP5430_BGAP_DTEMP_MPU_1_OFFSET               0x1E4
+#define OMAP5430_BGAP_DTEMP_MPU_2_OFFSET               0x1E8
+#define OMAP5430_BGAP_DTEMP_MPU_3_OFFSET               0x1EC
+#define OMAP5430_BGAP_DTEMP_MPU_4_OFFSET               0x1F0
+
+/* OMAP5430.MPU register offsets */
+#define OMAP5430_FUSE_OPP_BGAP_CORE                    0x8
+#define OMAP5430_TEMP_SENSOR_CORE_OFFSET               0x154
+#define OMAP5430_BGAP_THRESHOLD_CORE_OFFSET            0x1AC
+#define OMAP5430_BGAP_TSHUT_CORE_OFFSET                        0x1B8
+#define OMAP5430_BGAP_CUMUL_DTEMP_CORE_OFFSET          0x1C4
+#define OMAP5430_BGAP_DTEMP_CORE_0_OFFSET              0x208
+#define OMAP5430_BGAP_DTEMP_CORE_1_OFFSET              0x20C
+#define OMAP5430_BGAP_DTEMP_CORE_2_OFFSET              0x210
+#define OMAP5430_BGAP_DTEMP_CORE_3_OFFSET              0x214
+#define OMAP5430_BGAP_DTEMP_CORE_4_OFFSET              0x218
+
+/* OMAP5430.common register offsets */
+#define OMAP5430_BGAP_CTRL_OFFSET                      0x1A0
+#define OMAP5430_BGAP_STATUS_OFFSET                    0x1C8
+
+/**
+ * Register bitfields for OMAP5430
+ *
+ * All the macros bellow define the required bits for
+ * controlling temperature on OMAP5430. Bit defines are
+ * grouped by register.
+ */
+
+/* OMAP5430.TEMP_SENSOR */
+#define OMAP5430_BGAP_TEMP_SENSOR_SOC_MASK             BIT(12)
+#define OMAP5430_BGAP_TEMPSOFF_MASK                    BIT(11)
+#define OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK            BIT(10)
+#define OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK           (0x3ff << 0)
+
+/* OMAP5430.BANDGAP_CTRL */
+#define OMAP5430_MASK_SIDLEMODE_MASK                   (0x3 << 30)
+#define OMAP5430_MASK_COUNTER_DELAY_MASK               (0x7 << 27)
+#define OMAP5430_MASK_FREEZE_CORE_MASK                 BIT(23)
+#define OMAP5430_MASK_FREEZE_GPU_MASK                  BIT(22)
+#define OMAP5430_MASK_FREEZE_MPU_MASK                  BIT(21)
+#define OMAP5430_MASK_CLEAR_CORE_MASK                  BIT(20)
+#define OMAP5430_MASK_CLEAR_GPU_MASK                   BIT(19)
+#define OMAP5430_MASK_CLEAR_MPU_MASK                   BIT(18)
+#define OMAP5430_MASK_CLEAR_ACCUM_CORE_MASK            BIT(17)
+#define OMAP5430_MASK_CLEAR_ACCUM_GPU_MASK             BIT(16)
+#define OMAP5430_MASK_CLEAR_ACCUM_MPU_MASK             BIT(15)
+#define OMAP5430_MASK_HOT_CORE_MASK                    BIT(5)
+#define OMAP5430_MASK_COLD_CORE_MASK                   BIT(4)
+#define OMAP5430_MASK_HOT_GPU_MASK                     BIT(3)
+#define OMAP5430_MASK_COLD_GPU_MASK                    BIT(2)
+#define OMAP5430_MASK_HOT_MPU_MASK                     BIT(1)
+#define OMAP5430_MASK_COLD_MPU_MASK                    BIT(0)
+
+/* OMAP5430.BANDGAP_COUNTER */
+#define OMAP5430_COUNTER_MASK                          (0xffffff << 0)
+
+/* OMAP5430.BANDGAP_THRESHOLD */
+#define OMAP5430_T_HOT_MASK                            (0x3ff << 16)
+#define OMAP5430_T_COLD_MASK                           (0x3ff << 0)
+
+/* OMAP5430.TSHUT_THRESHOLD */
+#define OMAP5430_TSHUT_HOT_MASK                                (0x3ff << 16)
+#define OMAP5430_TSHUT_COLD_MASK                       (0x3ff << 0)
+
+/* OMAP5430.BANDGAP_CUMUL_DTEMP_MPU */
+#define OMAP5430_CUMUL_DTEMP_MPU_MASK                  (0xffffffff << 0)
+
+/* OMAP5430.BANDGAP_CUMUL_DTEMP_GPU */
+#define OMAP5430_CUMUL_DTEMP_GPU_MASK                  (0xffffffff << 0)
+
+/* OMAP5430.BANDGAP_CUMUL_DTEMP_CORE */
+#define OMAP5430_CUMUL_DTEMP_CORE_MASK                 (0xffffffff << 0)
+
+/* OMAP5430.BANDGAP_STATUS */
+#define OMAP5430_BGAP_ALERT_MASK                       BIT(31)
+#define OMAP5430_HOT_CORE_FLAG_MASK                    BIT(5)
+#define OMAP5430_COLD_CORE_FLAG_MASK                   BIT(4)
+#define OMAP5430_HOT_GPU_FLAG_MASK                     BIT(3)
+#define OMAP5430_COLD_GPU_FLAG_MASK                    BIT(2)
+#define OMAP5430_HOT_MPU_FLAG_MASK                     BIT(1)
+#define OMAP5430_COLD_MPU_FLAG_MASK                    BIT(0)
+
+/**
+ * Temperature limits and thresholds for OMAP5430
+ *
+ * All the macros bellow are definitions for handling the
+ * ADC conversions and representation of temperature limits
+ * and thresholds for OMAP5430. Definitions are grouped
+ * by temperature domain.
+ */
+
+/* OMAP5430.common temperature definitions */
+/* ADC conversion table limits */
+#define OMAP5430_ADC_START_VALUE                       540
+#define OMAP5430_ADC_END_VALUE                         945
+
+/* OMAP5430.GPU temperature definitions */
+/* bandgap clock limits */
+#define OMAP5430_GPU_MAX_FREQ                          1500000
+#define OMAP5430_GPU_MIN_FREQ                          1000000
+/* sensor limits */
+#define OMAP5430_GPU_MIN_TEMP                          -40000
+#define OMAP5430_GPU_MAX_TEMP                          125000
+#define OMAP5430_GPU_HYST_VAL                          5000
+/* interrupts thresholds */
+#define OMAP5430_GPU_TSHUT_HOT                         915
+#define OMAP5430_GPU_TSHUT_COLD                                900
+#define OMAP5430_GPU_T_HOT                             800
+#define OMAP5430_GPU_T_COLD                            795
+
+/* OMAP5430.MPU temperature definitions */
+/* bandgap clock limits */
+#define OMAP5430_MPU_MAX_FREQ                          1500000
+#define OMAP5430_MPU_MIN_FREQ                          1000000
+/* sensor limits */
+#define OMAP5430_MPU_MIN_TEMP                          -40000
+#define OMAP5430_MPU_MAX_TEMP                          125000
+#define OMAP5430_MPU_HYST_VAL                          5000
+/* interrupts thresholds */
+#define OMAP5430_MPU_TSHUT_HOT                         915
+#define OMAP5430_MPU_TSHUT_COLD                                900
+#define OMAP5430_MPU_T_HOT                             800
+#define OMAP5430_MPU_T_COLD                            795
+
+/* OMAP5430.CORE temperature definitions */
+/* bandgap clock limits */
+#define OMAP5430_CORE_MAX_FREQ                         1500000
+#define OMAP5430_CORE_MIN_FREQ                         1000000
+/* sensor limits */
+#define OMAP5430_CORE_MIN_TEMP                         -40000
+#define OMAP5430_CORE_MAX_TEMP                         125000
+#define OMAP5430_CORE_HYST_VAL                         5000
+/* interrupts thresholds */
+#define OMAP5430_CORE_TSHUT_HOT                                915
+#define OMAP5430_CORE_TSHUT_COLD                       900
+#define OMAP5430_CORE_T_HOT                            800
+#define OMAP5430_CORE_T_COLD                           795
+
+#endif /* __OMAP5XXX_BANDGAP_H */
diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.c b/drivers/thermal/ti-soc-thermal/ti-bandgap.c
new file mode 100644 (file)
index 0000000..9dfd471
--- /dev/null
@@ -0,0 +1,1556 @@
+/*
+ * TI Bandgap temperature sensor driver
+ *
+ * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: J Keerthy <j-keerthy@ti.com>
+ * Author: Moiz Sonasath <m-sonasath@ti.com>
+ * Couple of fixes, DT and MFD adaptation:
+ *   Eduardo Valentin <eduardo.valentin@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/reboot.h>
+#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"
+
+/***   Helper functions to access registers and their bitfields   ***/
+
+/**
+ * ti_bandgap_readl() - simple read helper function
+ * @bgp: pointer to ti_bandgap structure
+ * @reg: desired register (offset) to be read
+ *
+ * Helper function to read bandgap registers. It uses the io remapped area.
+ * Return: the register value.
+ */
+static u32 ti_bandgap_readl(struct ti_bandgap *bgp, u32 reg)
+{
+       return readl(bgp->base + reg);
+}
+
+/**
+ * ti_bandgap_writel() - simple write helper function
+ * @bgp: pointer to ti_bandgap structure
+ * @val: desired register value to be written
+ * @reg: desired register (offset) to be written
+ *
+ * Helper function to write bandgap registers. It uses the io remapped area.
+ */
+static void ti_bandgap_writel(struct ti_bandgap *bgp, u32 val, u32 reg)
+{
+       writel(val, bgp->base + reg);
+}
+
+/**
+ * DOC: macro to update bits.
+ *
+ * RMW_BITS() - used to read, modify and update bandgap bitfields.
+ *            The value passed will be shifted.
+ */
+#define RMW_BITS(bgp, id, reg, mask, val)                      \
+do {                                                           \
+       struct temp_sensor_registers *t;                        \
+       u32 r;                                                  \
+                                                               \
+       t = bgp->conf->sensors[(id)].registers;         \
+       r = ti_bandgap_readl(bgp, t->reg);                      \
+       r &= ~t->mask;                                          \
+       r |= (val) << __ffs(t->mask);                           \
+       ti_bandgap_writel(bgp, r, t->reg);                      \
+} while (0)
+
+/***   Basic helper functions   ***/
+
+/**
+ * ti_bandgap_power() - controls the power state of a bandgap device
+ * @bgp: pointer to ti_bandgap structure
+ * @on: desired power state (1 - on, 0 - off)
+ *
+ * Used to power on/off a bandgap device instance. Only used on those
+ * that features tempsoff bit.
+ *
+ * Return: 0 on success, -ENOTSUPP if tempsoff is not supported.
+ */
+static int ti_bandgap_power(struct ti_bandgap *bgp, bool on)
+{
+       int i, ret = 0;
+
+       if (!TI_BANDGAP_HAS(bgp, POWER_SWITCH)) {
+               ret = -ENOTSUPP;
+               goto exit;
+       }
+
+       for (i = 0; i < bgp->conf->sensor_count; i++)
+               /* active on 0 */
+               RMW_BITS(bgp, i, temp_sensor_ctrl, bgap_tempsoff_mask, !on);
+
+exit:
+       return ret;
+}
+
+/**
+ * ti_bandgap_read_temp() - helper function to read sensor temperature
+ * @bgp: pointer to ti_bandgap structure
+ * @id: bandgap sensor id
+ *
+ * Function to concentrate the steps to read sensor temperature register.
+ * This function is desired because, depending on bandgap device version,
+ * it might be needed to freeze the bandgap state machine, before fetching
+ * the register value.
+ *
+ * Return: temperature in ADC values.
+ */
+static u32 ti_bandgap_read_temp(struct ti_bandgap *bgp, int id)
+{
+       struct temp_sensor_registers *tsr;
+       u32 temp, reg;
+
+       tsr = bgp->conf->sensors[id].registers;
+       reg = tsr->temp_sensor_ctrl;
+
+       if (TI_BANDGAP_HAS(bgp, FREEZE_BIT)) {
+               RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1);
+               /*
+                * In case we cannot read from cur_dtemp / dtemp_0,
+                * then we read from the last valid temp read
+                */
+               reg = tsr->ctrl_dtemp_1;
+       }
+
+       /* read temperature */
+       temp = ti_bandgap_readl(bgp, reg);
+       temp &= tsr->bgap_dtemp_mask;
+
+       if (TI_BANDGAP_HAS(bgp, FREEZE_BIT))
+               RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 0);
+
+       return temp;
+}
+
+/***   IRQ handlers   ***/
+
+/**
+ * ti_bandgap_talert_irq_handler() - handles Temperature alert IRQs
+ * @irq: IRQ number
+ * @data: private data (struct ti_bandgap *)
+ *
+ * This is the Talert handler. Use it only if bandgap device features
+ * HAS(TALERT). This handler goes over all sensors and checks their
+ * conditions and acts accordingly. In case there are events pending,
+ * it will reset the event mask to wait for the opposite event (next event).
+ * Every time there is a new event, it will be reported to thermal layer.
+ *
+ * Return: IRQ_HANDLED
+ */
+static irqreturn_t ti_bandgap_talert_irq_handler(int irq, void *data)
+{
+       struct ti_bandgap *bgp = data;
+       struct temp_sensor_registers *tsr;
+       u32 t_hot = 0, t_cold = 0, ctrl;
+       int i;
+
+       spin_lock(&bgp->lock);
+       for (i = 0; i < bgp->conf->sensor_count; i++) {
+               tsr = bgp->conf->sensors[i].registers;
+               ctrl = ti_bandgap_readl(bgp, tsr->bgap_status);
+
+               /* Read the status of t_hot */
+               t_hot = ctrl & tsr->status_hot_mask;
+
+               /* Read the status of t_cold */
+               t_cold = ctrl & tsr->status_cold_mask;
+
+               if (!t_cold && !t_hot)
+                       continue;
+
+               ctrl = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
+               /*
+                * One TALERT interrupt: Two sources
+                * If the interrupt is due to t_hot then mask t_hot and
+                * and unmask t_cold else mask t_cold and unmask t_hot
+                */
+               if (t_hot) {
+                       ctrl &= ~tsr->mask_hot_mask;
+                       ctrl |= tsr->mask_cold_mask;
+               } else if (t_cold) {
+                       ctrl &= ~tsr->mask_cold_mask;
+                       ctrl |= tsr->mask_hot_mask;
+               }
+
+               ti_bandgap_writel(bgp, ctrl, tsr->bgap_mask_ctrl);
+
+               dev_dbg(bgp->dev,
+                       "%s: IRQ from %s sensor: hotevent %d coldevent %d\n",
+                       __func__, bgp->conf->sensors[i].domain,
+                       t_hot, t_cold);
+
+               /* report temperature to whom may concern */
+               if (bgp->conf->report_temperature)
+                       bgp->conf->report_temperature(bgp, i);
+       }
+       spin_unlock(&bgp->lock);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * ti_bandgap_tshut_irq_handler() - handles Temperature shutdown signal
+ * @irq: IRQ number
+ * @data: private data (unused)
+ *
+ * This is the Tshut handler. Use it only if bandgap device features
+ * HAS(TSHUT). If any sensor fires the Tshut signal, we simply shutdown
+ * the system.
+ *
+ * Return: IRQ_HANDLED
+ */
+static irqreturn_t ti_bandgap_tshut_irq_handler(int irq, void *data)
+{
+       pr_emerg("%s: TSHUT temperature reached. Needs shut down...\n",
+                __func__);
+
+       orderly_poweroff(true);
+
+       return IRQ_HANDLED;
+}
+
+/***   Helper functions which manipulate conversion ADC <-> mi Celsius   ***/
+
+/**
+ * ti_bandgap_adc_to_mcelsius() - converts an ADC value to mCelsius scale
+ * @bgp: struct ti_bandgap pointer
+ * @adc_val: value in ADC representation
+ * @t: address where to write the resulting temperature in mCelsius
+ *
+ * Simple conversion from ADC representation to mCelsius. In case the ADC value
+ * is out of the ADC conv table range, it returns -ERANGE, 0 on success.
+ * The conversion table is indexed by the ADC values.
+ *
+ * Return: 0 if conversion was successful, else -ERANGE in case the @adc_val
+ * argument is out of the ADC conv table range.
+ */
+static
+int ti_bandgap_adc_to_mcelsius(struct ti_bandgap *bgp, int adc_val, int *t)
+{
+       const struct ti_bandgap_data *conf = bgp->conf;
+       int ret = 0;
+
+       /* look up for temperature in the table and return the temperature */
+       if (adc_val < conf->adc_start_val || adc_val > conf->adc_end_val) {
+               ret = -ERANGE;
+               goto exit;
+       }
+
+       *t = bgp->conf->conv_table[adc_val - conf->adc_start_val];
+
+exit:
+       return ret;
+}
+
+/**
+ * ti_bandgap_mcelsius_to_adc() - converts a mCelsius value to ADC scale
+ * @bgp: struct ti_bandgap pointer
+ * @temp: value in mCelsius
+ * @adc: address where to write the resulting temperature in ADC representation
+ *
+ * Simple conversion from mCelsius to ADC values. In case the temp value
+ * is out of the ADC conv table range, it returns -ERANGE, 0 on success.
+ * The conversion table is indexed by the ADC values.
+ *
+ * Return: 0 if conversion was successful, else -ERANGE in case the @temp
+ * argument is out of the ADC conv table range.
+ */
+static
+int ti_bandgap_mcelsius_to_adc(struct ti_bandgap *bgp, long temp, int *adc)
+{
+       const struct ti_bandgap_data *conf = bgp->conf;
+       const int *conv_table = bgp->conf->conv_table;
+       int high, low, mid, ret = 0;
+
+       low = 0;
+       high = conf->adc_end_val - conf->adc_start_val;
+       mid = (high + low) / 2;
+
+       if (temp < conv_table[low] || temp > conv_table[high]) {
+               ret = -ERANGE;
+               goto exit;
+       }
+
+       while (low < high) {
+               if (temp < conv_table[mid])
+                       high = mid - 1;
+               else
+                       low = mid + 1;
+               mid = (low + high) / 2;
+       }
+
+       *adc = conf->adc_start_val + low;
+
+exit:
+       return ret;
+}
+
+/**
+ * ti_bandgap_add_hyst() - add hysteresis (in mCelsius) to an ADC value
+ * @bgp: struct ti_bandgap pointer
+ * @adc_val: temperature value in ADC representation
+ * @hyst_val: hysteresis value in mCelsius
+ * @sum: address where to write the resulting temperature (in ADC scale)
+ *
+ * Adds an hysteresis value (in mCelsius) to a ADC temperature value.
+ *
+ * Return: 0 on success, -ERANGE otherwise.
+ */
+static
+int ti_bandgap_add_hyst(struct ti_bandgap *bgp, int adc_val, int hyst_val,
+                       u32 *sum)
+{
+       int temp, ret;
+
+       /*
+        * Need to add in the mcelsius domain, so we have a temperature
+        * the conv_table range
+        */
+       ret = ti_bandgap_adc_to_mcelsius(bgp, adc_val, &temp);
+       if (ret < 0)
+               goto exit;
+
+       temp += hyst_val;
+
+       ret = ti_bandgap_mcelsius_to_adc(bgp, temp, sum);
+
+exit:
+       return ret;
+}
+
+/***   Helper functions handling device Alert/Shutdown signals   ***/
+
+/**
+ * ti_bandgap_unmask_interrupts() - unmasks the events of thot & tcold
+ * @bgp: struct ti_bandgap pointer
+ * @id: bandgap sensor id
+ * @t_hot: hot temperature value to trigger alert signal
+ * @t_cold: cold temperature value to trigger alert signal
+ *
+ * Checks the requested t_hot and t_cold values and configures the IRQ event
+ * masks accordingly. Call this function only if bandgap features HAS(TALERT).
+ */
+static void ti_bandgap_unmask_interrupts(struct ti_bandgap *bgp, int id,
+                                        u32 t_hot, u32 t_cold)
+{
+       struct temp_sensor_registers *tsr;
+       u32 temp, reg_val;
+
+       /* Read the current on die temperature */
+       temp = ti_bandgap_read_temp(bgp, id);
+
+       tsr = bgp->conf->sensors[id].registers;
+       reg_val = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
+
+       if (temp < t_hot)
+               reg_val |= tsr->mask_hot_mask;
+       else
+               reg_val &= ~tsr->mask_hot_mask;
+
+       if (t_cold < temp)
+               reg_val |= tsr->mask_cold_mask;
+       else
+               reg_val &= ~tsr->mask_cold_mask;
+       ti_bandgap_writel(bgp, reg_val, tsr->bgap_mask_ctrl);
+}
+
+/**
+ * ti_bandgap_update_alert_threshold() - sequence to update thresholds
+ * @bgp: struct ti_bandgap pointer
+ * @id: bandgap sensor id
+ * @val: value (ADC) of a new threshold
+ * @hot: desired threshold to be updated. true if threshold hot, false if
+ *       threshold cold
+ *
+ * It will program the required thresholds (hot and cold) for TALERT signal.
+ * This function can be used to update t_hot or t_cold, depending on @hot value.
+ * It checks the resulting t_hot and t_cold values, based on the new passed @val
+ * and configures the thresholds so that t_hot is always greater than t_cold.
+ * Call this function only if bandgap features HAS(TALERT).
+ *
+ * Return: 0 if no error, else corresponding error
+ */
+static int ti_bandgap_update_alert_threshold(struct ti_bandgap *bgp, int id,
+                                            int val, bool hot)
+{
+       struct temp_sensor_data *ts_data = bgp->conf->sensors[id].ts_data;
+       struct temp_sensor_registers *tsr;
+       u32 thresh_val, reg_val, t_hot, t_cold;
+       int err = 0;
+
+       tsr = bgp->conf->sensors[id].registers;
+
+       /* obtain the current value */
+       thresh_val = ti_bandgap_readl(bgp, tsr->bgap_threshold);
+       t_cold = (thresh_val & tsr->threshold_tcold_mask) >>
+               __ffs(tsr->threshold_tcold_mask);
+       t_hot = (thresh_val & tsr->threshold_thot_mask) >>
+               __ffs(tsr->threshold_thot_mask);
+       if (hot)
+               t_hot = val;
+       else
+               t_cold = val;
+
+       if (t_cold > t_hot) {
+               if (hot)
+                       err = ti_bandgap_add_hyst(bgp, t_hot,
+                                                 -ts_data->hyst_val,
+                                                 &t_cold);
+               else
+                       err = ti_bandgap_add_hyst(bgp, t_cold,
+                                                 ts_data->hyst_val,
+                                                 &t_hot);
+       }
+
+       /* write the new threshold values */
+       reg_val = thresh_val &
+                 ~(tsr->threshold_thot_mask | tsr->threshold_tcold_mask);
+       reg_val |= (t_hot << __ffs(tsr->threshold_thot_mask)) |
+                  (t_cold << __ffs(tsr->threshold_tcold_mask));
+       ti_bandgap_writel(bgp, reg_val, tsr->bgap_threshold);
+
+       if (err) {
+               dev_err(bgp->dev, "failed to reprogram thot threshold\n");
+               err = -EIO;
+               goto exit;
+       }
+
+       ti_bandgap_unmask_interrupts(bgp, id, t_hot, t_cold);
+exit:
+       return err;
+}
+
+/**
+ * ti_bandgap_validate() - helper to check the sanity of a struct ti_bandgap
+ * @bgp: struct ti_bandgap pointer
+ * @id: bandgap sensor id
+ *
+ * Checks if the bandgap pointer is valid and if the sensor id is also
+ * applicable.
+ *
+ * Return: 0 if no errors, -EINVAL for invalid @bgp pointer or -ERANGE if
+ * @id cannot index @bgp sensors.
+ */
+static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id)
+{
+       int ret = 0;
+
+       if (!bgp || IS_ERR(bgp)) {
+               pr_err("%s: invalid bandgap pointer\n", __func__);
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       if ((id < 0) || (id >= bgp->conf->sensor_count)) {
+               dev_err(bgp->dev, "%s: sensor id out of range (%d)\n",
+                       __func__, id);
+               ret = -ERANGE;
+       }
+
+exit:
+       return ret;
+}
+
+/**
+ * _ti_bandgap_write_threshold() - helper to update TALERT t_cold or t_hot
+ * @bgp: struct ti_bandgap pointer
+ * @id: bandgap sensor id
+ * @val: value (mCelsius) of a new threshold
+ * @hot: desired threshold to be updated. true if threshold hot, false if
+ *       threshold cold
+ *
+ * It will update the required thresholds (hot and cold) for TALERT signal.
+ * This function can be used to update t_hot or t_cold, depending on @hot value.
+ * Validates the mCelsius range and update the requested threshold.
+ * Call this function only if bandgap features HAS(TALERT).
+ *
+ * Return: 0 if no error, else corresponding error value.
+ */
+static int _ti_bandgap_write_threshold(struct ti_bandgap *bgp, int id, int val,
+                                      bool hot)
+{
+       struct temp_sensor_data *ts_data;
+       struct temp_sensor_registers *tsr;
+       u32 adc_val;
+       int ret;
+
+       ret = ti_bandgap_validate(bgp, id);
+       if (ret)
+               goto exit;
+
+       if (!TI_BANDGAP_HAS(bgp, TALERT)) {
+               ret = -ENOTSUPP;
+               goto exit;
+       }
+
+       ts_data = bgp->conf->sensors[id].ts_data;
+       tsr = bgp->conf->sensors[id].registers;
+       if (hot) {
+               if (val < ts_data->min_temp + ts_data->hyst_val)
+                       ret = -EINVAL;
+       } else {
+               if (val > ts_data->max_temp + ts_data->hyst_val)
+                       ret = -EINVAL;
+       }
+
+       if (ret)
+               goto exit;
+
+       ret = ti_bandgap_mcelsius_to_adc(bgp, val, &adc_val);
+       if (ret < 0)
+               goto exit;
+
+       spin_lock(&bgp->lock);
+       ret = ti_bandgap_update_alert_threshold(bgp, id, adc_val, hot);
+       spin_unlock(&bgp->lock);
+
+exit:
+       return ret;
+}
+
+/**
+ * _ti_bandgap_read_threshold() - helper to read TALERT t_cold or t_hot
+ * @bgp: struct ti_bandgap pointer
+ * @id: bandgap sensor id
+ * @val: value (mCelsius) of a threshold
+ * @hot: desired threshold to be read. true if threshold hot, false if
+ *       threshold cold
+ *
+ * It will fetch the required thresholds (hot and cold) for TALERT signal.
+ * This function can be used to read t_hot or t_cold, depending on @hot value.
+ * Call this function only if bandgap features HAS(TALERT).
+ *
+ * Return: 0 if no error, -ENOTSUPP if it has no TALERT support, or the
+ * corresponding error value if some operation fails.
+ */
+static int _ti_bandgap_read_threshold(struct ti_bandgap *bgp, int id,
+                                     int *val, bool hot)
+{
+       struct temp_sensor_registers *tsr;
+       u32 temp, mask;
+       int ret = 0;
+
+       ret = ti_bandgap_validate(bgp, id);
+       if (ret)
+               goto exit;
+
+       if (!TI_BANDGAP_HAS(bgp, TALERT)) {
+               ret = -ENOTSUPP;
+               goto exit;
+       }
+
+       tsr = bgp->conf->sensors[id].registers;
+       if (hot)
+               mask = tsr->threshold_thot_mask;
+       else
+               mask = tsr->threshold_tcold_mask;
+
+       temp = ti_bandgap_readl(bgp, tsr->bgap_threshold);
+       temp = (temp & mask) >> __ffs(mask);
+       ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);
+       if (ret) {
+               dev_err(bgp->dev, "failed to read thot\n");
+               ret = -EIO;
+               goto exit;
+       }
+
+       *val = temp;
+
+exit:
+       return ret;
+}
+
+/***   Exposed APIs   ***/
+
+/**
+ * ti_bandgap_read_thot() - reads sensor current thot
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @thot: resulting current thot value
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_read_thot(struct ti_bandgap *bgp, int id, int *thot)
+{
+       return _ti_bandgap_read_threshold(bgp, id, thot, true);
+}
+
+/**
+ * ti_bandgap_write_thot() - sets sensor current thot
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @val: desired thot value
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_write_thot(struct ti_bandgap *bgp, int id, int val)
+{
+       return _ti_bandgap_write_threshold(bgp, id, val, true);
+}
+
+/**
+ * ti_bandgap_read_tcold() - reads sensor current tcold
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @tcold: resulting current tcold value
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_read_tcold(struct ti_bandgap *bgp, int id, int *tcold)
+{
+       return _ti_bandgap_read_threshold(bgp, id, tcold, false);
+}
+
+/**
+ * ti_bandgap_write_tcold() - sets the sensor tcold
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @val: desired tcold value
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_write_tcold(struct ti_bandgap *bgp, int id, int val)
+{
+       return _ti_bandgap_write_threshold(bgp, id, val, false);
+}
+
+/**
+ * ti_bandgap_read_counter() - read the sensor counter
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @interval: resulting update interval in miliseconds
+ */
+static void ti_bandgap_read_counter(struct ti_bandgap *bgp, int id,
+                                   int *interval)
+{
+       struct temp_sensor_registers *tsr;
+       int time;
+
+       tsr = bgp->conf->sensors[id].registers;
+       time = ti_bandgap_readl(bgp, tsr->bgap_counter);
+       time = (time & tsr->counter_mask) >>
+                                       __ffs(tsr->counter_mask);
+       time = time * 1000 / bgp->clk_rate;
+       *interval = time;
+}
+
+/**
+ * ti_bandgap_read_counter_delay() - read the sensor counter delay
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @interval: resulting update interval in miliseconds
+ */
+static void ti_bandgap_read_counter_delay(struct ti_bandgap *bgp, int id,
+                                         int *interval)
+{
+       struct temp_sensor_registers *tsr;
+       int reg_val;
+
+       tsr = bgp->conf->sensors[id].registers;
+
+       reg_val = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
+       reg_val = (reg_val & tsr->mask_counter_delay_mask) >>
+                               __ffs(tsr->mask_counter_delay_mask);
+       switch (reg_val) {
+       case 0:
+               *interval = 0;
+               break;
+       case 1:
+               *interval = 1;
+               break;
+       case 2:
+               *interval = 10;
+               break;
+       case 3:
+               *interval = 100;
+               break;
+       case 4:
+               *interval = 250;
+               break;
+       case 5:
+               *interval = 500;
+               break;
+       default:
+               dev_warn(bgp->dev, "Wrong counter delay value read from register %X",
+                        reg_val);
+       }
+}
+
+/**
+ * ti_bandgap_read_update_interval() - read the sensor update interval
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @interval: resulting update interval in miliseconds
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id,
+                                   int *interval)
+{
+       int ret = 0;
+
+       ret = ti_bandgap_validate(bgp, id);
+       if (ret)
+               goto exit;
+
+       if (!TI_BANDGAP_HAS(bgp, COUNTER) &&
+           !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) {
+               ret = -ENOTSUPP;
+               goto exit;
+       }
+
+       if (TI_BANDGAP_HAS(bgp, COUNTER)) {
+               ti_bandgap_read_counter(bgp, id, interval);
+               goto exit;
+       }
+
+       ti_bandgap_read_counter_delay(bgp, id, interval);
+exit:
+       return ret;
+}
+
+/**
+ * ti_bandgap_write_counter_delay() - set the counter_delay
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @interval: desired update interval in miliseconds
+ *
+ * Return: 0 on success or the proper error code
+ */
+static int ti_bandgap_write_counter_delay(struct ti_bandgap *bgp, int id,
+                                         u32 interval)
+{
+       int rval;
+
+       switch (interval) {
+       case 0: /* Immediate conversion */
+               rval = 0x0;
+               break;
+       case 1: /* Conversion after ever 1ms */
+               rval = 0x1;
+               break;
+       case 10: /* Conversion after ever 10ms */
+               rval = 0x2;
+               break;
+       case 100: /* Conversion after ever 100ms */
+               rval = 0x3;
+               break;
+       case 250: /* Conversion after ever 250ms */
+               rval = 0x4;
+               break;
+       case 500: /* Conversion after ever 500ms */
+               rval = 0x5;
+               break;
+       default:
+               dev_warn(bgp->dev, "Delay %d ms is not supported\n", interval);
+               return -EINVAL;
+       }
+
+       spin_lock(&bgp->lock);
+       RMW_BITS(bgp, id, bgap_mask_ctrl, mask_counter_delay_mask, rval);
+       spin_unlock(&bgp->lock);
+
+       return 0;
+}
+
+/**
+ * ti_bandgap_write_counter() - set the bandgap sensor counter
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @interval: desired update interval in miliseconds
+ */
+static void ti_bandgap_write_counter(struct ti_bandgap *bgp, int id,
+                                    u32 interval)
+{
+       interval = interval * bgp->clk_rate / 1000;
+       spin_lock(&bgp->lock);
+       RMW_BITS(bgp, id, bgap_counter, counter_mask, interval);
+       spin_unlock(&bgp->lock);
+}
+
+/**
+ * ti_bandgap_write_update_interval() - set the update interval
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @interval: desired update interval in miliseconds
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_write_update_interval(struct ti_bandgap *bgp,
+                                    int id, u32 interval)
+{
+       int ret = ti_bandgap_validate(bgp, id);
+       if (ret)
+               goto exit;
+
+       if (!TI_BANDGAP_HAS(bgp, COUNTER) &&
+           !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) {
+               ret = -ENOTSUPP;
+               goto exit;
+       }
+
+       if (TI_BANDGAP_HAS(bgp, COUNTER)) {
+               ti_bandgap_write_counter(bgp, id, interval);
+               goto exit;
+       }
+
+       ret = ti_bandgap_write_counter_delay(bgp, id, interval);
+exit:
+       return ret;
+}
+
+/**
+ * ti_bandgap_read_temperature() - report current temperature
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @temperature: resulting temperature
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id,
+                               int *temperature)
+{
+       u32 temp;
+       int ret;
+
+       ret = ti_bandgap_validate(bgp, id);
+       if (ret)
+               return ret;
+
+       spin_lock(&bgp->lock);
+       temp = ti_bandgap_read_temp(bgp, id);
+       spin_unlock(&bgp->lock);
+
+       ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);
+       if (ret)
+               return -EIO;
+
+       *temperature = temp;
+
+       return 0;
+}
+
+/**
+ * ti_bandgap_set_sensor_data() - helper function to store thermal
+ * framework related data.
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @data: thermal framework related data to be stored
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data)
+{
+       int ret = ti_bandgap_validate(bgp, id);
+       if (ret)
+               return ret;
+
+       bgp->regval[id].data = data;
+
+       return 0;
+}
+
+/**
+ * ti_bandgap_get_sensor_data() - helper function to get thermal
+ * framework related data.
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ *
+ * Return: data stored by set function with sensor id on success or NULL
+ */
+void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id)
+{
+       int ret = ti_bandgap_validate(bgp, id);
+       if (ret)
+               return ERR_PTR(ret);
+
+       return bgp->regval[id].data;
+}
+
+/***   Helper functions used during device initialization   ***/
+
+/**
+ * ti_bandgap_force_single_read() - executes 1 single ADC conversion
+ * @bgp: pointer to struct ti_bandgap
+ * @id: sensor id which it is desired to read 1 temperature
+ *
+ * Used to initialize the conversion state machine and set it to a valid
+ * state. Called during device initialization and context restore events.
+ *
+ * Return: 0
+ */
+static int
+ti_bandgap_force_single_read(struct ti_bandgap *bgp, int id)
+{
+       u32 temp = 0, counter = 1000;
+
+       /* Select single conversion mode */
+       if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
+               RMW_BITS(bgp, id, bgap_mode_ctrl, mode_ctrl_mask, 0);
+
+       /* Start of Conversion = 1 */
+       RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 1);
+       /* Wait until DTEMP is updated */
+       temp = ti_bandgap_read_temp(bgp, id);
+
+       while ((temp == 0) && --counter)
+               temp = ti_bandgap_read_temp(bgp, id);
+       /* REVISIT: Check correct condition for end of conversion */
+
+       /* Start of Conversion = 0 */
+       RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 0);
+
+       return 0;
+}
+
+/**
+ * ti_bandgap_set_continous_mode() - One time enabling of continuous mode
+ * @bgp: pointer to struct ti_bandgap
+ *
+ * Call this function only if HAS(MODE_CONFIG) is set. As this driver may
+ * be used for junction temperature monitoring, it is desirable that the
+ * sensors are operational all the time, so that alerts are generated
+ * properly.
+ *
+ * Return: 0
+ */
+static int ti_bandgap_set_continuous_mode(struct ti_bandgap *bgp)
+{
+       int i;
+
+       for (i = 0; i < bgp->conf->sensor_count; i++) {
+               /* Perform a single read just before enabling continuous */
+               ti_bandgap_force_single_read(bgp, i);
+               RMW_BITS(bgp, i, bgap_mode_ctrl, mode_ctrl_mask, 1);
+       }
+
+       return 0;
+}
+
+/**
+ * ti_bandgap_get_trend() - To fetch the temperature trend of a sensor
+ * @bgp: pointer to struct ti_bandgap
+ * @id: id of the individual sensor
+ * @trend: Pointer to trend.
+ *
+ * This function needs to be called to fetch the temperature trend of a
+ * Particular sensor. The function computes the difference in temperature
+ * w.r.t time. For the bandgaps with built in history buffer the temperatures
+ * are read from the buffer and for those without the Buffer -ENOTSUPP is
+ * returned.
+ *
+ * Return: 0 if no error, else return corresponding error. If no
+ *             error then the trend value is passed on to trend parameter
+ */
+int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
+{
+       struct temp_sensor_registers *tsr;
+       u32 temp1, temp2, reg1, reg2;
+       int t1, t2, interval, ret = 0;
+
+       ret = ti_bandgap_validate(bgp, id);
+       if (ret)
+               goto exit;
+
+       if (!TI_BANDGAP_HAS(bgp, HISTORY_BUFFER) ||
+           !TI_BANDGAP_HAS(bgp, FREEZE_BIT)) {
+               ret = -ENOTSUPP;
+               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;
+
+       /* read temperature from history buffer */
+       temp1 = ti_bandgap_readl(bgp, reg1);
+       temp1 &= tsr->bgap_dtemp_mask;
+
+       temp2 = ti_bandgap_readl(bgp, reg2);
+       temp2 &= tsr->bgap_dtemp_mask;
+
+       /* Convert from adc values to mCelsius temperature */
+       ret = ti_bandgap_adc_to_mcelsius(bgp, temp1, &t1);
+       if (ret)
+               goto unfreeze;
+
+       ret = ti_bandgap_adc_to_mcelsius(bgp, temp2, &t2);
+       if (ret)
+               goto unfreeze;
+
+       /* Fetch the update interval */
+       ret = ti_bandgap_read_update_interval(bgp, id, &interval);
+       if (ret || !interval)
+               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;
+}
+
+/**
+ * ti_bandgap_tshut_init() - setup and initialize tshut handling
+ * @bgp: pointer to struct ti_bandgap
+ * @pdev: pointer to device struct platform_device
+ *
+ * Call this function only in case the bandgap features HAS(TSHUT).
+ * In this case, the driver needs to handle the TSHUT signal as an IRQ.
+ * The IRQ is wired as a GPIO, and for this purpose, it is required
+ * to specify which GPIO line is used. TSHUT IRQ is fired anytime
+ * one of the bandgap sensors violates the TSHUT high/hot threshold.
+ * And in that case, the system must go off.
+ *
+ * Return: 0 if no error, else error status
+ */
+static int ti_bandgap_tshut_init(struct ti_bandgap *bgp,
+                                struct platform_device *pdev)
+{
+       int gpio_nr = bgp->tshut_gpio;
+       int status;
+
+       /* Request for gpio_86 line */
+       status = gpio_request(gpio_nr, "tshut");
+       if (status < 0) {
+               dev_err(bgp->dev, "Could not request for TSHUT GPIO:%i\n", 86);
+               return status;
+       }
+       status = gpio_direction_input(gpio_nr);
+       if (status) {
+               dev_err(bgp->dev, "Cannot set input TSHUT GPIO %d\n", gpio_nr);
+               return status;
+       }
+
+       status = request_irq(gpio_to_irq(gpio_nr), ti_bandgap_tshut_irq_handler,
+                            IRQF_TRIGGER_RISING, "tshut", NULL);
+       if (status) {
+               gpio_free(gpio_nr);
+               dev_err(bgp->dev, "request irq failed for TSHUT");
+       }
+
+       return 0;
+}
+
+/**
+ * ti_bandgap_alert_init() - setup and initialize talert handling
+ * @bgp: pointer to struct ti_bandgap
+ * @pdev: pointer to device struct platform_device
+ *
+ * Call this function only in case the bandgap features HAS(TALERT).
+ * In this case, the driver needs to handle the TALERT signals as an IRQs.
+ * TALERT is a normal IRQ and it is fired any time thresholds (hot or cold)
+ * are violated. In these situation, the driver must reprogram the thresholds,
+ * accordingly to specified policy.
+ *
+ * Return: 0 if no error, else return corresponding error.
+ */
+static int ti_bandgap_talert_init(struct ti_bandgap *bgp,
+                                 struct platform_device *pdev)
+{
+       int ret;
+
+       bgp->irq = platform_get_irq(pdev, 0);
+       if (bgp->irq < 0) {
+               dev_err(&pdev->dev, "get_irq failed\n");
+               return bgp->irq;
+       }
+       ret = request_threaded_irq(bgp->irq, NULL,
+                                  ti_bandgap_talert_irq_handler,
+                                  IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                                  "talert", bgp);
+       if (ret) {
+               dev_err(&pdev->dev, "Request threaded irq failed.\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct of_device_id of_ti_bandgap_match[];
+/**
+ * ti_bandgap_build() - parse DT and setup a struct ti_bandgap
+ * @pdev: pointer to device struct platform_device
+ *
+ * Used to read the device tree properties accordingly to the bandgap
+ * matching version. Based on bandgap version and its capabilities it
+ * will build a struct ti_bandgap out of the required DT entries.
+ *
+ * Return: valid bandgap structure if successful, else returns ERR_PTR
+ * return value must be verified with IS_ERR.
+ */
+static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       const struct of_device_id *of_id;
+       struct ti_bandgap *bgp;
+       struct resource *res;
+       int i;
+
+       /* just for the sake */
+       if (!node) {
+               dev_err(&pdev->dev, "no platform information available\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       bgp = devm_kzalloc(&pdev->dev, sizeof(*bgp), GFP_KERNEL);
+       if (!bgp) {
+               dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       of_id = of_match_device(of_ti_bandgap_match, &pdev->dev);
+       if (of_id)
+               bgp->conf = of_id->data;
+
+       /* register shadow for context save and restore */
+       bgp->regval = devm_kzalloc(&pdev->dev, sizeof(*bgp->regval) *
+                                  bgp->conf->sensor_count, GFP_KERNEL);
+       if (!bgp) {
+               dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       i = 0;
+       do {
+               void __iomem *chunk;
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+               if (!res)
+                       break;
+               chunk = devm_ioremap_resource(&pdev->dev, res);
+               if (i == 0)
+                       bgp->base = chunk;
+               if (IS_ERR(chunk))
+                       return ERR_CAST(chunk);
+
+               i++;
+       } while (res);
+
+       if (TI_BANDGAP_HAS(bgp, TSHUT)) {
+               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);
+                       return ERR_PTR(-EINVAL);
+               }
+       }
+
+       return bgp;
+}
+
+/***   Device driver call backs   ***/
+
+static
+int ti_bandgap_probe(struct platform_device *pdev)
+{
+       struct ti_bandgap *bgp;
+       int clk_rate, ret = 0, i;
+
+       bgp = ti_bandgap_build(pdev);
+       if (IS_ERR(bgp)) {
+               dev_err(&pdev->dev, "failed to fetch platform data\n");
+               return PTR_ERR(bgp);
+       }
+       bgp->dev = &pdev->dev;
+
+       if (TI_BANDGAP_HAS(bgp, TSHUT)) {
+               ret = ti_bandgap_tshut_init(bgp, pdev);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "failed to initialize system tshut IRQ\n");
+                       return ret;
+               }
+       }
+
+       bgp->fclock = clk_get(NULL, bgp->conf->fclock_name);
+       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(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;
+       }
+
+       for (i = 0; i < bgp->conf->sensor_count; i++) {
+               struct temp_sensor_registers *tsr;
+               u32 val;
+
+               tsr = bgp->conf->sensors[i].registers;
+               /*
+                * check if the efuse has a non-zero value if not
+                * it is an untrimmed sample and the temperatures
+                * may not be accurate
+                */
+               val = ti_bandgap_readl(bgp, tsr->bgap_efuse);
+               if (ret || !val)
+                       dev_info(&pdev->dev,
+                                "Non-trimmed BGAP, Temp not accurate\n");
+       }
+
+       clk_rate = clk_round_rate(bgp->div_clk,
+                                 bgp->conf->sensors[0].ts_data->max_freq);
+       if (clk_rate < bgp->conf->sensors[0].ts_data->min_freq ||
+           clk_rate == 0xffffffff) {
+               ret = -ENODEV;
+               dev_err(&pdev->dev, "wrong clock rate (%d)\n", clk_rate);
+               goto put_clks;
+       }
+
+       ret = clk_set_rate(bgp->div_clk, clk_rate);
+       if (ret)
+               dev_err(&pdev->dev, "Cannot re-set clock rate. Continuing\n");
+
+       bgp->clk_rate = clk_rate;
+       if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
+               clk_prepare_enable(bgp->fclock);
+
+
+       spin_lock_init(&bgp->lock);
+       bgp->dev = &pdev->dev;
+       platform_set_drvdata(pdev, bgp);
+
+       ti_bandgap_power(bgp, true);
+
+       /* Set default counter to 1 for now */
+       if (TI_BANDGAP_HAS(bgp, COUNTER))
+               for (i = 0; i < bgp->conf->sensor_count; i++)
+                       RMW_BITS(bgp, i, bgap_counter, counter_mask, 1);
+
+       /* Set default thresholds for alert and shutdown */
+       for (i = 0; i < bgp->conf->sensor_count; i++) {
+               struct temp_sensor_data *ts_data;
+
+               ts_data = bgp->conf->sensors[i].ts_data;
+
+               if (TI_BANDGAP_HAS(bgp, TALERT)) {
+                       /* Set initial Talert thresholds */
+                       RMW_BITS(bgp, i, bgap_threshold,
+                                threshold_tcold_mask, ts_data->t_cold);
+                       RMW_BITS(bgp, i, bgap_threshold,
+                                threshold_thot_mask, ts_data->t_hot);
+                       /* Enable the alert events */
+                       RMW_BITS(bgp, i, bgap_mask_ctrl, mask_hot_mask, 1);
+                       RMW_BITS(bgp, i, bgap_mask_ctrl, mask_cold_mask, 1);
+               }
+
+               if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) {
+                       /* Set initial Tshut thresholds */
+                       RMW_BITS(bgp, i, tshut_threshold,
+                                tshut_hot_mask, ts_data->tshut_hot);
+                       RMW_BITS(bgp, i, tshut_threshold,
+                                tshut_cold_mask, ts_data->tshut_cold);
+               }
+       }
+
+       if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
+               ti_bandgap_set_continuous_mode(bgp);
+
+       /* Set .250 seconds time as default counter */
+       if (TI_BANDGAP_HAS(bgp, COUNTER))
+               for (i = 0; i < bgp->conf->sensor_count; i++)
+                       RMW_BITS(bgp, i, bgap_counter, counter_mask,
+                                bgp->clk_rate / 4);
+
+       /* Every thing is good? Then expose the sensors */
+       for (i = 0; i < bgp->conf->sensor_count; i++) {
+               char *domain;
+
+               if (bgp->conf->sensors[i].register_cooling) {
+                       ret = bgp->conf->sensors[i].register_cooling(bgp, i);
+                       if (ret)
+                               goto remove_sensors;
+               }
+
+               if (bgp->conf->expose_sensor) {
+                       domain = bgp->conf->sensors[i].domain;
+                       ret = bgp->conf->expose_sensor(bgp, i, domain);
+                       if (ret)
+                               goto remove_last_cooling;
+               }
+       }
+
+       /*
+        * Enable the Interrupts once everything is set. Otherwise irq handler
+        * might be called as soon as it is enabled where as rest of framework
+        * is still getting initialised.
+        */
+       if (TI_BANDGAP_HAS(bgp, TALERT)) {
+               ret = ti_bandgap_talert_init(bgp, pdev);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to initialize Talert IRQ\n");
+                       i = bgp->conf->sensor_count;
+                       goto disable_clk;
+               }
+       }
+
+       return 0;
+
+remove_last_cooling:
+       if (bgp->conf->sensors[i].unregister_cooling)
+               bgp->conf->sensors[i].unregister_cooling(bgp, i);
+remove_sensors:
+       for (i--; i >= 0; i--) {
+               if (bgp->conf->sensors[i].unregister_cooling)
+                       bgp->conf->sensors[i].unregister_cooling(bgp, i);
+               if (bgp->conf->remove_sensor)
+                       bgp->conf->remove_sensor(bgp, i);
+       }
+       ti_bandgap_power(bgp, false);
+disable_clk:
+       if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
+               clk_disable_unprepare(bgp->fclock);
+put_clks:
+       clk_put(bgp->fclock);
+       clk_put(bgp->div_clk);
+free_irqs:
+       if (TI_BANDGAP_HAS(bgp, TSHUT)) {
+               free_irq(gpio_to_irq(bgp->tshut_gpio), NULL);
+               gpio_free(bgp->tshut_gpio);
+       }
+
+       return ret;
+}
+
+static
+int ti_bandgap_remove(struct platform_device *pdev)
+{
+       struct ti_bandgap *bgp = platform_get_drvdata(pdev);
+       int i;
+
+       /* First thing is to remove sensor interfaces */
+       for (i = 0; i < bgp->conf->sensor_count; i++) {
+               if (bgp->conf->sensors[i].unregister_cooling)
+                       bgp->conf->sensors[i].unregister_cooling(bgp, i);
+
+               if (bgp->conf->remove_sensor)
+                       bgp->conf->remove_sensor(bgp, i);
+       }
+
+       ti_bandgap_power(bgp, false);
+
+       if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
+               clk_disable_unprepare(bgp->fclock);
+       clk_put(bgp->fclock);
+       clk_put(bgp->div_clk);
+
+       if (TI_BANDGAP_HAS(bgp, TALERT))
+               free_irq(bgp->irq, bgp);
+
+       if (TI_BANDGAP_HAS(bgp, TSHUT)) {
+               free_irq(gpio_to_irq(bgp->tshut_gpio), NULL);
+               gpio_free(bgp->tshut_gpio);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int ti_bandgap_save_ctxt(struct ti_bandgap *bgp)
+{
+       int i;
+
+       for (i = 0; i < bgp->conf->sensor_count; i++) {
+               struct temp_sensor_registers *tsr;
+               struct temp_sensor_regval *rval;
+
+               rval = &bgp->regval[i];
+               tsr = bgp->conf->sensors[i].registers;
+
+               if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
+                       rval->bg_mode_ctrl = ti_bandgap_readl(bgp,
+                                                       tsr->bgap_mode_ctrl);
+               if (TI_BANDGAP_HAS(bgp, COUNTER))
+                       rval->bg_counter = ti_bandgap_readl(bgp,
+                                                       tsr->bgap_counter);
+               if (TI_BANDGAP_HAS(bgp, TALERT)) {
+                       rval->bg_threshold = ti_bandgap_readl(bgp,
+                                                       tsr->bgap_threshold);
+                       rval->bg_ctrl = ti_bandgap_readl(bgp,
+                                                  tsr->bgap_mask_ctrl);
+               }
+
+               if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG))
+                       rval->tshut_threshold = ti_bandgap_readl(bgp,
+                                                  tsr->tshut_threshold);
+       }
+
+       return 0;
+}
+
+static int ti_bandgap_restore_ctxt(struct ti_bandgap *bgp)
+{
+       int i;
+
+       for (i = 0; i < bgp->conf->sensor_count; i++) {
+               struct temp_sensor_registers *tsr;
+               struct temp_sensor_regval *rval;
+               u32 val = 0;
+
+               rval = &bgp->regval[i];
+               tsr = bgp->conf->sensors[i].registers;
+
+               if (TI_BANDGAP_HAS(bgp, COUNTER))
+                       val = ti_bandgap_readl(bgp, tsr->bgap_counter);
+
+               if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG))
+                       ti_bandgap_writel(bgp, rval->tshut_threshold,
+                                         tsr->tshut_threshold);
+               /* Force immediate temperature measurement and update
+                * of the DTEMP field
+                */
+               ti_bandgap_force_single_read(bgp, i);
+
+               if (TI_BANDGAP_HAS(bgp, COUNTER))
+                       ti_bandgap_writel(bgp, rval->bg_counter,
+                                         tsr->bgap_counter);
+               if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
+                       ti_bandgap_writel(bgp, rval->bg_mode_ctrl,
+                                         tsr->bgap_mode_ctrl);
+               if (TI_BANDGAP_HAS(bgp, TALERT)) {
+                       ti_bandgap_writel(bgp, rval->bg_threshold,
+                                         tsr->bgap_threshold);
+                       ti_bandgap_writel(bgp, rval->bg_ctrl,
+                                         tsr->bgap_mask_ctrl);
+               }
+       }
+
+       return 0;
+}
+
+static int ti_bandgap_suspend(struct device *dev)
+{
+       struct ti_bandgap *bgp = dev_get_drvdata(dev);
+       int err;
+
+       err = ti_bandgap_save_ctxt(bgp);
+       ti_bandgap_power(bgp, false);
+
+       if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
+               clk_disable_unprepare(bgp->fclock);
+
+       return err;
+}
+
+static int ti_bandgap_resume(struct device *dev)
+{
+       struct ti_bandgap *bgp = dev_get_drvdata(dev);
+
+       if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
+               clk_prepare_enable(bgp->fclock);
+
+       ti_bandgap_power(bgp, true);
+
+       return ti_bandgap_restore_ctxt(bgp);
+}
+static const struct dev_pm_ops ti_bandgap_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(ti_bandgap_suspend,
+                               ti_bandgap_resume)
+};
+
+#define DEV_PM_OPS     (&ti_bandgap_dev_pm_ops)
+#else
+#define DEV_PM_OPS     NULL
+#endif
+
+static const struct of_device_id of_ti_bandgap_match[] = {
+#ifdef CONFIG_OMAP4_THERMAL
+       {
+               .compatible = "ti,omap4430-bandgap",
+               .data = (void *)&omap4430_data,
+       },
+       {
+               .compatible = "ti,omap4460-bandgap",
+               .data = (void *)&omap4460_data,
+       },
+       {
+               .compatible = "ti,omap4470-bandgap",
+               .data = (void *)&omap4470_data,
+       },
+#endif
+#ifdef CONFIG_OMAP5_THERMAL
+       {
+               .compatible = "ti,omap5430-bandgap",
+               .data = (void *)&omap5430_data,
+       },
+#endif
+#ifdef CONFIG_DRA752_THERMAL
+       {
+               .compatible = "ti,dra752-bandgap",
+               .data = (void *)&dra752_data,
+       },
+#endif
+       /* Sentinel */
+       { },
+};
+MODULE_DEVICE_TABLE(of, of_ti_bandgap_match);
+
+static struct platform_driver ti_bandgap_sensor_driver = {
+       .probe = ti_bandgap_probe,
+       .remove = ti_bandgap_remove,
+       .driver = {
+                       .name = "ti-soc-thermal",
+                       .pm = DEV_PM_OPS,
+                       .of_match_table = of_ti_bandgap_match,
+       },
+};
+
+module_platform_driver(ti_bandgap_sensor_driver);
+
+MODULE_DESCRIPTION("OMAP4+ bandgap temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ti-soc-thermal");
+MODULE_AUTHOR("Texas Instrument Inc.");
diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.h b/drivers/thermal/ti-soc-thermal/ti-bandgap.h
new file mode 100644 (file)
index 0000000..b3adf72
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * OMAP4 Bandgap temperature sensor driver
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Contact:
+ *   Eduardo Valentin <eduardo.valentin@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef __TI_BANDGAP_H
+#define __TI_BANDGAP_H
+
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/err.h>
+
+/**
+ * DOC: bandgap driver data structure
+ * ==================================
+ *
+ *   +----------+----------------+
+ *   | struct temp_sensor_regval |
+ *   +---------------------------+
+ *              * (Array of)
+ *              |
+ *              |
+ *   +-------------------+   +-----------------+
+ *   | struct ti_bandgap |-->| struct device * |
+ *   +----------+--------+   +-----------------+
+ *              |
+ *              |
+ *              V
+ *   +------------------------+
+ *   | struct ti_bandgap_data |
+ *   +------------------------+
+ *              |
+ *              |
+ *              * (Array of)
+ * +------------+------------------------------------------------------+
+ * | +----------+------------+   +-------------------------+           |
+ * | | struct ti_temp_sensor |-->| struct temp_sensor_data |           |
+ * | +-----------------------+   +------------+------------+           |
+ * |            |                                                      |
+ * |            +                                                      |
+ * |            V                                                      |
+ * | +----------+-------------------+                                  |
+ * | | struct temp_sensor_registers |                                  |
+ * | +------------------------------+                                  |
+ * |                                                                   |
+ * +-------------------------------------------------------------------+
+ *
+ * Above is a simple diagram describing how the data structure below
+ * are organized. For each bandgap device there should be a ti_bandgap_data
+ * containing the device instance configuration, as well as, an array of
+ * sensors, representing every sensor instance present in this bandgap.
+ */
+
+/**
+ * struct temp_sensor_registers - descriptor to access registers and bitfields
+ * @temp_sensor_ctrl: TEMP_SENSOR_CTRL register offset
+ * @bgap_tempsoff_mask: mask to temp_sensor_ctrl.tempsoff
+ * @bgap_soc_mask: mask to temp_sensor_ctrl.soc
+ * @bgap_eocz_mask: mask to temp_sensor_ctrl.eocz
+ * @bgap_dtemp_mask: mask to temp_sensor_ctrl.dtemp
+ * @bgap_mask_ctrl: BANDGAP_MASK_CTRL register offset
+ * @mask_hot_mask: mask to bandgap_mask_ctrl.mask_hot
+ * @mask_cold_mask: mask to bandgap_mask_ctrl.mask_cold
+ * @mask_sidlemode_mask: mask to bandgap_mask_ctrl.mask_sidlemode
+ * @mask_counter_delay_mask: mask to bandgap_mask_ctrl.mask_counter_delay
+ * @mask_freeze_mask: mask to bandgap_mask_ctrl.mask_free
+ * @mask_clear_mask: mask to bandgap_mask_ctrl.mask_clear
+ * @mask_clear_accum_mask: mask to bandgap_mask_ctrl.mask_clear_accum
+ * @bgap_mode_ctrl: BANDGAP_MODE_CTRL register offset
+ * @mode_ctrl_mask: mask to bandgap_mode_ctrl.mode_ctrl
+ * @bgap_counter: BANDGAP_COUNTER register offset
+ * @counter_mask: mask to bandgap_counter.counter
+ * @bgap_threshold: BANDGAP_THRESHOLD register offset (TALERT thresholds)
+ * @threshold_thot_mask: mask to bandgap_threhold.thot
+ * @threshold_tcold_mask: mask to bandgap_threhold.tcold
+ * @tshut_threshold: TSHUT_THRESHOLD register offset (TSHUT thresholds)
+ * @tshut_efuse_mask: mask to tshut_threshold.tshut_efuse
+ * @tshut_efuse_shift: shift to tshut_threshold.tshut_efuse
+ * @tshut_hot_mask: mask to tshut_threhold.thot
+ * @tshut_cold_mask: mask to tshut_threhold.thot
+ * @bgap_status: BANDGAP_STATUS register offset
+ * @status_clean_stop_mask: mask to bandgap_status.clean_stop
+ * @status_bgap_alert_mask: mask to bandgap_status.bandgap_alert
+ * @status_hot_mask: mask to bandgap_status.hot
+ * @status_cold_mask: mask to bandgap_status.cold
+ * @bgap_cumul_dtemp: BANDGAP_CUMUL_DTEMP register offset
+ * @ctrl_dtemp_0: CTRL_DTEMP0 register offset
+ * @ctrl_dtemp_1: CTRL_DTEMP1 register offset
+ * @ctrl_dtemp_2: CTRL_DTEMP2 register offset
+ * @ctrl_dtemp_3: CTRL_DTEMP3 register offset
+ * @ctrl_dtemp_4: CTRL_DTEMP4 register offset
+ * @bgap_efuse: BANDGAP_EFUSE register offset
+ *
+ * The register offsets and bitfields might change across
+ * OMAP and variants versions. Hence this struct serves as a
+ * descriptor map on how to access the registers and the bitfields.
+ *
+ * This descriptor contains registers of all versions of bandgap chips.
+ * Not all versions will use all registers, depending on the available
+ * features. Please read TRMs for descriptive explanation on each bitfield.
+ */
+
+struct temp_sensor_registers {
+       u32     temp_sensor_ctrl;
+       u32     bgap_tempsoff_mask;
+       u32     bgap_soc_mask;
+       u32     bgap_eocz_mask; /* not used: but needs revisit */
+       u32     bgap_dtemp_mask;
+
+       u32     bgap_mask_ctrl;
+       u32     mask_hot_mask;
+       u32     mask_cold_mask;
+       u32     mask_sidlemode_mask; /* not used: but may be needed for pm */
+       u32     mask_counter_delay_mask;
+       u32     mask_freeze_mask;
+       u32     mask_clear_mask; /* not used: but needed for trending */
+       u32     mask_clear_accum_mask; /* not used: but needed for trending */
+
+       u32     bgap_mode_ctrl;
+       u32     mode_ctrl_mask;
+
+       u32     bgap_counter;
+       u32     counter_mask;
+
+       u32     bgap_threshold;
+       u32     threshold_thot_mask;
+       u32     threshold_tcold_mask;
+
+       u32     tshut_threshold;
+       u32     tshut_efuse_mask; /* not used */
+       u32     tshut_efuse_shift; /* not used */
+       u32     tshut_hot_mask;
+       u32     tshut_cold_mask;
+
+       u32     bgap_status;
+       u32     status_clean_stop_mask; /* not used: but needed for trending */
+       u32     status_bgap_alert_mask; /* not used */
+       u32     status_hot_mask;
+       u32     status_cold_mask;
+
+       u32     bgap_cumul_dtemp; /* not used: but needed for trending */
+       u32     ctrl_dtemp_0; /* not used: but needed for trending */
+       u32     ctrl_dtemp_1; /* not used: but needed for trending */
+       u32     ctrl_dtemp_2; /* not used: but needed for trending */
+       u32     ctrl_dtemp_3; /* not used: but needed for trending */
+       u32     ctrl_dtemp_4; /* not used: but needed for trending */
+       u32     bgap_efuse;
+};
+
+/**
+ * struct temp_sensor_data - The thresholds and limits for temperature sensors.
+ * @tshut_hot: temperature to trigger a thermal reset (initial value)
+ * @tshut_cold: temp to get the plat out of reset due to thermal (init val)
+ * @t_hot: temperature to trigger a thermal alert (high initial value)
+ * @t_cold: temperature to trigger a thermal alert (low initial value)
+ * @min_freq: sensor minimum clock rate
+ * @max_freq: sensor maximum clock rate
+ * @max_temp: sensor maximum temperature
+ * @min_temp: sensor minimum temperature
+ * @hyst_val: temperature hysteresis considered while converting ADC values
+ * @update_int1: update interval
+ * @update_int2: update interval
+ *
+ * This data structure will hold the required thresholds and temperature limits
+ * for a specific temperature sensor, like shutdown temperature, alert
+ * temperature, clock / rate used, ADC conversion limits and update intervals
+ */
+struct temp_sensor_data {
+       u32     tshut_hot;
+       u32     tshut_cold;
+       u32     t_hot;
+       u32     t_cold;
+       u32     min_freq;
+       u32     max_freq;
+       int     max_temp;
+       int     min_temp;
+       int     hyst_val;
+       u32     update_int1; /* not used */
+       u32     update_int2; /* not used */
+};
+
+struct ti_bandgap_data;
+
+/**
+ * struct temp_sensor_regval - temperature sensor register values and priv data
+ * @bg_mode_ctrl: temp sensor control register value
+ * @bg_ctrl: bandgap ctrl register value
+ * @bg_counter: bandgap counter value
+ * @bg_threshold: bandgap threshold register value
+ * @tshut_threshold: bandgap tshut register value
+ * @data: private data
+ *
+ * Data structure to save and restore bandgap register set context. Only
+ * required registers are shadowed, when needed.
+ */
+struct temp_sensor_regval {
+       u32                     bg_mode_ctrl;
+       u32                     bg_ctrl;
+       u32                     bg_counter;
+       u32                     bg_threshold;
+       u32                     tshut_threshold;
+       void                    *data;
+};
+
+/**
+ * struct ti_bandgap - bandgap device structure
+ * @dev: struct device pointer
+ * @base: io memory base address
+ * @conf: struct with bandgap configuration set (# sensors, conv_table, etc)
+ * @regval: temperature sensor register values
+ * @fclock: pointer to functional clock of temperature sensor
+ * @div_clk: pointer to divider clock of temperature sensor fclk
+ * @lock: spinlock for ti_bandgap structure
+ * @irq: MPU IRQ number for thermal alert
+ * @tshut_gpio: GPIO where Tshut signal is routed
+ * @clk_rate: Holds current clock rate
+ *
+ * The bandgap device structure representing the bandgap device instance.
+ * It holds most of the dynamic stuff. Configurations and sensor specific
+ * entries are inside the @conf structure.
+ */
+struct ti_bandgap {
+       struct device                   *dev;
+       void __iomem                    *base;
+       const struct ti_bandgap_data    *conf;
+       struct temp_sensor_regval       *regval;
+       struct clk                      *fclock;
+       struct clk                      *div_clk;
+       spinlock_t                      lock; /* shields this struct */
+       int                             irq;
+       int                             tshut_gpio;
+       u32                             clk_rate;
+};
+
+/**
+ * struct ti_temp_sensor - bandgap temperature sensor configuration data
+ * @ts_data: pointer to struct with thresholds, limits of temperature sensor
+ * @registers: pointer to the list of register offsets and bitfields
+ * @domain: the name of the domain where the sensor is located
+ * @slope: sensor gradient slope info for hotspot extrapolation equation
+ * @constant: sensor gradient const info for hotspot extrapolation equation
+ * @slope_pcb: sensor gradient slope info for hotspot extrapolation equation
+ *             with no external influence
+ * @constant_pcb: sensor gradient const info for hotspot extrapolation equation
+ *             with no external influence
+ * @register_cooling: function to describe how this sensor is going to be cooled
+ * @unregister_cooling: function to release cooling data
+ *
+ * Data structure to describe a temperature sensor handled by a bandgap device.
+ * It should provide configuration details on this sensor, such as how to
+ * access the registers affecting this sensor, shadow register buffer, how to
+ * assess the gradient from hotspot, how to cooldown the domain when sensor
+ * reports too hot temperature.
+ */
+struct ti_temp_sensor {
+       struct temp_sensor_data         *ts_data;
+       struct temp_sensor_registers    *registers;
+       char                            *domain;
+       /* for hotspot extrapolation */
+       const int                       slope;
+       const int                       constant;
+       const int                       slope_pcb;
+       const int                       constant_pcb;
+       int (*register_cooling)(struct ti_bandgap *bgp, int id);
+       int (*unregister_cooling)(struct ti_bandgap *bgp, int id);
+};
+
+/**
+ * DOC: ti bandgap feature types
+ *
+ * TI_BANDGAP_FEATURE_TSHUT - used when the thermal shutdown signal output
+ *      of a bandgap device instance is routed to the processor. This means
+ *      the system must react and perform the shutdown by itself (handle an
+ *      IRQ, for instance).
+ *
+ * TI_BANDGAP_FEATURE_TSHUT_CONFIG - used when the bandgap device has control
+ *      over the thermal shutdown configuration. This means that the thermal
+ *      shutdown thresholds are programmable, for instance.
+ *
+ * TI_BANDGAP_FEATURE_TALERT - used when the bandgap device instance outputs
+ *      a signal representing violation of programmable alert thresholds.
+ *
+ * TI_BANDGAP_FEATURE_MODE_CONFIG - used when it is possible to choose which
+ *      mode, continuous or one shot, the bandgap device instance will operate.
+ *
+ * TI_BANDGAP_FEATURE_COUNTER - used when the bandgap device instance allows
+ *      programming the update interval of its internal state machine.
+ *
+ * TI_BANDGAP_FEATURE_POWER_SWITCH - used when the bandgap device allows
+ *      itself to be switched on/off.
+ *
+ * TI_BANDGAP_FEATURE_CLK_CTRL - used when the clocks feeding the bandgap
+ *      device are gateable or not.
+ *
+ * TI_BANDGAP_FEATURE_FREEZE_BIT - used when the bandgap device features
+ *      a history buffer that its update can be freezed/unfreezed.
+ *
+ * TI_BANDGAP_FEATURE_COUNTER_DELAY - used when the bandgap device features
+ *     a delay programming based on distinct values.
+ *
+ * TI_BANDGAP_FEATURE_HISTORY_BUFFER - used when the bandgap device features
+ *     a history buffer of temperatures.
+ *
+ * TI_BANDGAP_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 TI_BANDGAP_FEATURE_TSHUT               BIT(0)
+#define TI_BANDGAP_FEATURE_TSHUT_CONFIG                BIT(1)
+#define TI_BANDGAP_FEATURE_TALERT              BIT(2)
+#define TI_BANDGAP_FEATURE_MODE_CONFIG         BIT(3)
+#define TI_BANDGAP_FEATURE_COUNTER             BIT(4)
+#define TI_BANDGAP_FEATURE_POWER_SWITCH                BIT(5)
+#define TI_BANDGAP_FEATURE_CLK_CTRL            BIT(6)
+#define TI_BANDGAP_FEATURE_FREEZE_BIT          BIT(7)
+#define TI_BANDGAP_FEATURE_COUNTER_DELAY       BIT(8)
+#define TI_BANDGAP_FEATURE_HISTORY_BUFFER      BIT(9)
+#define TI_BANDGAP_HAS(b, f)                   \
+                       ((b)->conf->features & TI_BANDGAP_FEATURE_ ## f)
+
+/**
+ * struct ti_bandgap_data - ti bandgap data configuration structure
+ * @features: a bitwise flag set to describe the device features
+ * @conv_table: Pointer to ADC to temperature conversion table
+ * @adc_start_val: ADC conversion table starting value
+ * @adc_end_val: ADC conversion table ending value
+ * @fclock_name: clock name of the functional clock
+ * @div_ck_name: clock name of the clock divisor
+ * @sensor_count: count of temperature sensor within this bandgap device
+ * @report_temperature: callback to report thermal alert to thermal API
+ * @expose_sensor: callback to export sensor to thermal API
+ * @remove_sensor: callback to destroy sensor from thermal API
+ * @sensors: array of sensors present in this bandgap instance
+ *
+ * This is a data structure which should hold most of the static configuration
+ * of a bandgap device instance. It should describe which features this instance
+ * is capable of, the clock names to feed this device, the amount of sensors and
+ * their configuration representation, and how to export and unexport them to
+ * a thermal API.
+ */
+struct ti_bandgap_data {
+       unsigned int                    features;
+       const int                       *conv_table;
+       u32                             adc_start_val;
+       u32                             adc_end_val;
+       char                            *fclock_name;
+       char                            *div_ck_name;
+       int                             sensor_count;
+       int (*report_temperature)(struct ti_bandgap *bgp, int id);
+       int (*expose_sensor)(struct ti_bandgap *bgp, int id, char *domain);
+       int (*remove_sensor)(struct ti_bandgap *bgp, int id);
+
+       /* this needs to be at the end */
+       struct ti_temp_sensor           sensors[];
+};
+
+int ti_bandgap_read_thot(struct ti_bandgap *bgp, int id, int *thot);
+int ti_bandgap_write_thot(struct ti_bandgap *bgp, int id, int val);
+int ti_bandgap_read_tcold(struct ti_bandgap *bgp, int id, int *tcold);
+int ti_bandgap_write_tcold(struct ti_bandgap *bgp, int id, int val);
+int ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id,
+                                   int *interval);
+int ti_bandgap_write_update_interval(struct ti_bandgap *bgp, int id,
+                                    u32 interval);
+int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id,
+                                 int *temperature);
+int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data);
+void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id);
+int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend);
+
+#ifdef CONFIG_OMAP4_THERMAL
+extern const struct ti_bandgap_data omap4430_data;
+extern const struct ti_bandgap_data omap4460_data;
+extern const struct ti_bandgap_data omap4470_data;
+#else
+#define omap4430_data                                  NULL
+#define omap4460_data                                  NULL
+#define omap4470_data                                  NULL
+#endif
+
+#ifdef CONFIG_OMAP5_THERMAL
+extern const struct ti_bandgap_data omap5430_data;
+#else
+#define omap5430_data                                  NULL
+#endif
+
+#ifdef CONFIG_DRA752_THERMAL
+extern const struct ti_bandgap_data dra752_data;
+#else
+#define dra752_data                                    NULL
+#endif
+#endif
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
new file mode 100644 (file)
index 0000000..4c5f55c
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * OMAP thermal driver interface
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Contact:
+ *   Eduardo Valentin <eduardo.valentin@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/workqueue.h>
+#include <linux/thermal.h>
+#include <linux/cpufreq.h>
+#include <linux/cpumask.h>
+#include <linux/cpu_cooling.h>
+
+#include "ti-thermal.h"
+#include "ti-bandgap.h"
+
+/* common data structures */
+struct ti_thermal_data {
+       struct thermal_zone_device *ti_thermal;
+       struct thermal_zone_device *pcb_tz;
+       struct thermal_cooling_device *cool_dev;
+       struct ti_bandgap *bgp;
+       enum thermal_device_mode mode;
+       struct work_struct thermal_wq;
+       int sensor_id;
+};
+
+static void ti_thermal_work(struct work_struct *work)
+{
+       struct ti_thermal_data *data = container_of(work,
+                                       struct ti_thermal_data, thermal_wq);
+
+       thermal_zone_device_update(data->ti_thermal);
+
+       dev_dbg(&data->ti_thermal->device, "updated thermal zone %s\n",
+               data->ti_thermal->type);
+}
+
+/**
+ * ti_thermal_hotspot_temperature - returns sensor extrapolated temperature
+ * @t: omap sensor temperature
+ * @s: omap sensor slope value
+ * @c: omap sensor const value
+ */
+static inline int ti_thermal_hotspot_temperature(int t, int s, int c)
+{
+       int delta = t * s / 1000 + c;
+
+       if (delta < 0)
+               delta = 0;
+
+       return t + delta;
+}
+
+/* thermal zone ops */
+/* Get temperature callback function for thermal zone*/
+static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
+                                     unsigned long *temp)
+{
+       struct thermal_zone_device *pcb_tz = NULL;
+       struct ti_thermal_data *data = thermal->devdata;
+       struct ti_bandgap *bgp;
+       const struct ti_temp_sensor *s;
+       int ret, tmp, slope, constant;
+       unsigned long pcb_temp;
+
+       if (!data)
+               return 0;
+
+       bgp = data->bgp;
+       s = &bgp->conf->sensors[data->sensor_id];
+
+       ret = ti_bandgap_read_temperature(bgp, data->sensor_id, &tmp);
+       if (ret)
+               return ret;
+
+       /* Default constants */
+       slope = s->slope;
+       constant = s->constant;
+
+       pcb_tz = data->pcb_tz;
+       /* In case pcb zone is available, use the extrapolation rule with it */
+       if (!IS_ERR(pcb_tz)) {
+               ret = thermal_zone_get_temp(pcb_tz, &pcb_temp);
+               if (!ret) {
+                       tmp -= pcb_temp; /* got a valid PCB temp */
+                       slope = s->slope_pcb;
+                       constant = s->constant_pcb;
+               } else {
+                       dev_err(bgp->dev,
+                               "Failed to read PCB state. Using defaults\n");
+               }
+       }
+       *temp = ti_thermal_hotspot_temperature(tmp, slope, constant);
+
+       return ret;
+}
+
+/* Bind callback functions for thermal zone */
+static int ti_thermal_bind(struct thermal_zone_device *thermal,
+                          struct thermal_cooling_device *cdev)
+{
+       struct ti_thermal_data *data = thermal->devdata;
+       int id;
+
+       if (!data || IS_ERR(data))
+               return -ENODEV;
+
+       /* check if this is the cooling device we registered */
+       if (data->cool_dev != cdev)
+               return 0;
+
+       id = data->sensor_id;
+
+       /* Simple thing, two trips, one passive another critical */
+       return thermal_zone_bind_cooling_device(thermal, 0, cdev,
+       /* bind with min and max states defined by cpu_cooling */
+                                               THERMAL_NO_LIMIT,
+                                               THERMAL_NO_LIMIT);
+}
+
+/* Unbind callback functions for thermal zone */
+static int ti_thermal_unbind(struct thermal_zone_device *thermal,
+                            struct thermal_cooling_device *cdev)
+{
+       struct ti_thermal_data *data = thermal->devdata;
+
+       if (!data || IS_ERR(data))
+               return -ENODEV;
+
+       /* check if this is the cooling device we registered */
+       if (data->cool_dev != cdev)
+               return 0;
+
+       /* Simple thing, two trips, one passive another critical */
+       return thermal_zone_unbind_cooling_device(thermal, 0, cdev);
+}
+
+/* Get mode callback functions for thermal zone */
+static int ti_thermal_get_mode(struct thermal_zone_device *thermal,
+                              enum thermal_device_mode *mode)
+{
+       struct ti_thermal_data *data = thermal->devdata;
+
+       if (data)
+               *mode = data->mode;
+
+       return 0;
+}
+
+/* Set mode callback functions for thermal zone */
+static int ti_thermal_set_mode(struct thermal_zone_device *thermal,
+                              enum thermal_device_mode mode)
+{
+       struct ti_thermal_data *data = thermal->devdata;
+
+       if (!data->ti_thermal) {
+               dev_notice(&thermal->device, "thermal zone not registered\n");
+               return 0;
+       }
+
+       mutex_lock(&data->ti_thermal->lock);
+
+       if (mode == THERMAL_DEVICE_ENABLED)
+               data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
+       else
+               data->ti_thermal->polling_delay = 0;
+
+       mutex_unlock(&data->ti_thermal->lock);
+
+       data->mode = mode;
+       thermal_zone_device_update(data->ti_thermal);
+       dev_dbg(&thermal->device, "thermal polling set for duration=%d msec\n",
+               data->ti_thermal->polling_delay);
+
+       return 0;
+}
+
+/* Get trip type callback functions for thermal zone */
+static int ti_thermal_get_trip_type(struct thermal_zone_device *thermal,
+                                   int trip, enum thermal_trip_type *type)
+{
+       if (!ti_thermal_is_valid_trip(trip))
+               return -EINVAL;
+
+       if (trip + 1 == OMAP_TRIP_NUMBER)
+               *type = THERMAL_TRIP_CRITICAL;
+       else
+               *type = THERMAL_TRIP_PASSIVE;
+
+       return 0;
+}
+
+/* Get trip temperature callback functions for thermal zone */
+static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal,
+                                   int trip, unsigned long *temp)
+{
+       if (!ti_thermal_is_valid_trip(trip))
+               return -EINVAL;
+
+       *temp = ti_thermal_get_trip_value(trip);
+
+       return 0;
+}
+
+/* Get the temperature trend callback functions for thermal zone */
+static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
+                               int trip, enum thermal_trend *trend)
+{
+       struct ti_thermal_data *data = thermal->devdata;
+       struct ti_bandgap *bgp;
+       int id, tr, ret = 0;
+
+       bgp = data->bgp;
+       id = data->sensor_id;
+
+       ret = ti_bandgap_get_trend(bgp, id, &tr);
+       if (ret)
+               return ret;
+
+       if (tr > 0)
+               *trend = THERMAL_TREND_RAISING;
+       else if (tr < 0)
+               *trend = THERMAL_TREND_DROPPING;
+       else
+               *trend = THERMAL_TREND_STABLE;
+
+       return 0;
+}
+
+/* Get critical temperature callback functions for thermal zone */
+static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal,
+                                   unsigned long *temp)
+{
+       /* shutdown zone */
+       return ti_thermal_get_trip_temp(thermal, OMAP_TRIP_NUMBER - 1, temp);
+}
+
+static struct thermal_zone_device_ops ti_thermal_ops = {
+       .get_temp = ti_thermal_get_temp,
+       .get_trend = ti_thermal_get_trend,
+       .bind = ti_thermal_bind,
+       .unbind = ti_thermal_unbind,
+       .get_mode = ti_thermal_get_mode,
+       .set_mode = ti_thermal_set_mode,
+       .get_trip_type = ti_thermal_get_trip_type,
+       .get_trip_temp = ti_thermal_get_trip_temp,
+       .get_crit_temp = ti_thermal_get_crit_temp,
+};
+
+static struct ti_thermal_data
+*ti_thermal_build_data(struct ti_bandgap *bgp, int id)
+{
+       struct ti_thermal_data *data;
+
+       data = devm_kzalloc(bgp->dev, sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               dev_err(bgp->dev, "kzalloc fail\n");
+               return NULL;
+       }
+       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);
+
+       return data;
+}
+
+int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
+                            char *domain)
+{
+       struct ti_thermal_data *data;
+
+       data = ti_bandgap_get_sensor_data(bgp, id);
+
+       if (!data || IS_ERR(data))
+               data = ti_thermal_build_data(bgp, id);
+
+       if (!data)
+               return -EINVAL;
+
+       /* Create thermal zone */
+       data->ti_thermal = thermal_zone_device_register(domain,
+                               OMAP_TRIP_NUMBER, 0, data, &ti_thermal_ops,
+                               NULL, FAST_TEMP_MONITORING_RATE,
+                               FAST_TEMP_MONITORING_RATE);
+       if (IS_ERR(data->ti_thermal)) {
+               dev_err(bgp->dev, "thermal zone device is NULL\n");
+               return PTR_ERR(data->ti_thermal);
+       }
+       data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
+       ti_bandgap_set_sensor_data(bgp, id, data);
+
+       return 0;
+}
+
+int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id)
+{
+       struct ti_thermal_data *data;
+
+       data = ti_bandgap_get_sensor_data(bgp, id);
+
+       thermal_zone_device_unregister(data->ti_thermal);
+
+       return 0;
+}
+
+int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id)
+{
+       struct ti_thermal_data *data;
+
+       data = ti_bandgap_get_sensor_data(bgp, id);
+
+       schedule_work(&data->thermal_wq);
+
+       return 0;
+}
+
+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 (!data || IS_ERR(data))
+               data = ti_thermal_build_data(bgp, id);
+
+       if (!data)
+               return -EINVAL;
+
+       if (!cpufreq_get_current_driver()) {
+               dev_dbg(bgp->dev, "no cpufreq driver yet\n");
+               return -EPROBE_DEFER;
+       }
+
+       /* Register cooling device */
+       data->cool_dev = cpufreq_cooling_register(cpu_present_mask);
+       if (IS_ERR(data->cool_dev)) {
+               dev_err(bgp->dev,
+                       "Failed to register cpufreq cooling device\n");
+               return PTR_ERR(data->cool_dev);
+       }
+       ti_bandgap_set_sensor_data(bgp, id, data);
+
+       return 0;
+}
+
+int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
+{
+       struct ti_thermal_data *data;
+
+       data = ti_bandgap_get_sensor_data(bgp, id);
+       cpufreq_cooling_unregister(data->cool_dev);
+
+       return 0;
+}
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal.h b/drivers/thermal/ti-soc-thermal/ti-thermal.h
new file mode 100644 (file)
index 0000000..f8b7ffe
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * OMAP thermal definitions
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Contact:
+ *   Eduardo Valentin <eduardo.valentin@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef __TI_THERMAL_H
+#define __TI_THERMAL_H
+
+#include "ti-bandgap.h"
+
+/* sensors gradient and offsets */
+#define OMAP_GRADIENT_SLOPE_4430                               0
+#define OMAP_GRADIENT_CONST_4430                               20000
+#define OMAP_GRADIENT_SLOPE_4460                               348
+#define OMAP_GRADIENT_CONST_4460                               -9301
+#define OMAP_GRADIENT_SLOPE_4470                               308
+#define OMAP_GRADIENT_CONST_4470                               -7896
+
+#define OMAP_GRADIENT_SLOPE_5430_CPU                           65
+#define OMAP_GRADIENT_CONST_5430_CPU                           -1791
+#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
+#define OMAP_GRADIENT_SLOPE_W_PCB_4460                         1142
+#define OMAP_GRADIENT_CONST_W_PCB_4460                         -393
+#define OMAP_GRADIENT_SLOPE_W_PCB_4470                         1063
+#define OMAP_GRADIENT_CONST_W_PCB_4470                         -477
+
+#define OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU                     100
+#define OMAP_GRADIENT_CONST_W_PCB_5430_CPU                     484
+#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
+#define OMAP_TRIP_SHUTDOWN                                     125000
+#define OMAP_TRIP_NUMBER                                       2
+#define OMAP_TRIP_STEP                                                 \
+       ((OMAP_TRIP_SHUTDOWN - OMAP_TRIP_HOT) / (OMAP_TRIP_NUMBER - 1))
+
+/* Update rates */
+#define FAST_TEMP_MONITORING_RATE                              250
+
+/* helper macros */
+/**
+ * ti_thermal_get_trip_value - returns trip temperature based on index
+ * @i: trip index
+ */
+#define ti_thermal_get_trip_value(i)                                   \
+       (OMAP_TRIP_HOT + ((i) * OMAP_TRIP_STEP))
+
+/**
+ * ti_thermal_is_valid_trip - check for trip index
+ * @i: trip index
+ */
+#define ti_thermal_is_valid_trip(trip)                         \
+       ((trip) >= 0 && (trip) < OMAP_TRIP_NUMBER)
+
+#ifdef CONFIG_TI_THERMAL
+int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, char *domain);
+int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id);
+int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id);
+int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id);
+int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id);
+#else
+static inline
+int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, char *domain)
+{
+       return 0;
+}
+
+static inline
+int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id)
+{
+       return 0;
+}
+
+static inline
+int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id)
+{
+       return 0;
+}
+
+static inline
+int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
+{
+       return 0;
+}
+
+static inline
+int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
+{
+       return 0;
+}
+#endif
+#endif
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 d07b6af3a9379db82927677a5915d9bae01d7874..76a8daadff47f43ef4c594076902efc34cee086f 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 5f91c7a599461be843f923d5513a882f135c2dbc..e2a1f50bd93c4b7740c6592d5446c965ec107b04 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 7cacd6ae818e3ef957efe728eeb9641ccbf42071..0ff33396eef3ac6e99a78af1db7874d82cff8480 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 817e9e19cecf75c34253f0ebbb75d7e9282e383a..7a9111de80542b0877f9cef36a1f788353b4e2ab 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 2817013bceb1537a80a2e3ec58a91a339f4115f0..4263d011392c08f752e8c00cf49e64da770115e4 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 259ad282ae5dc129ba88882493e444d517a1f582..c488da5db7c7f1b0bda8e3b7559971ebfba0c442 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 6f3fbc48a6c73a2fc27d847176874ad65b68d83c..a9807dea3887af0afe44e545784f70d46efa40dd 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 8b9226da3f546d3d1900fbdb4068cde9497fa503..017a1e8a8f6fcf4eb092fa48584aef00dddf5f17 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 654e9afb11f578aa497802e77280f2f5bfa8b70e..e0441c34db1cf81dff8e327fa38400f0bb44bbd3 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 8ca5ac71b8452210517c128b6b7c12e7af832b4f..027be91db139c43eaadd5e12727c2b18c1a65bcc 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 7014202972259f4d7046d5f4a110fe9a0cedef37..06adf31a92484a6f32f01ab71c2dd76c6553c920 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 1ee45bc85f672100e0b4e2728c8e60d42bc5880a..a73ea217f24dc79a0f92a95cca39c416e828a6b9 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 60aa5ad09a2fdb74a457ecadf0130f056f114c8e..e58cf0001cee10bbe789fdbf7d7fe94260f4eaa9 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 64adcf99ff33893f1eb71b4c181dba4df739a8f3..42298cd23c73842e6a4ec7f8434428b56e700098 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 0098810df69da6bb795b85a573ca28d7bd5a7609..1f572c00a1bec2f13e68861e6dda971e6fef5d40 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 a7ce73029f5989de1cf3c53fc318bcfebfc99c87..1aba255b5879a10243c5426abba873103ff15696 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 7460d349df5954cd9ca1a7bde00297f8bdcf9375..362085d7ad8fc1787f234039ecb4b9620237657b 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
@@ -1083,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
@@ -1109,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
@@ -1183,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 ec268995b261c4074ed0bc056802e84f02331554..2f26a0b47ddc1f701cbd101cc81be713c0e04d77 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
@@ -144,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 7a715e3e6828ee2ede8b80676860d3fc6d280e22..b178e717ef09e025b6984b00b68184e05934f8e8 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 b2b80d4ac8188b2c9ea06be7e2e56c207427a646..a14a58d9d1107bdbc31a0ff28f0fcad8fdc71906 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 70387582843ff1f6c60d868c8c2807d41ad11c66..213225edd0599a6aa7aa933ead68570fa8dddda9 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 367445009c64b98e5361eda0082f01f9db4dd707..f09c54e9686fad94104a7679aa7a7675d32d3ebd 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 f5ad10546fc9fe46ec6abe182ec09ee7665af30f..575f37a965a471ba93a77a4bdda5840f0dc7b8e0 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 20376698938252e789e5839ce70e5839dd5d5d22..e621098bf6630e17ff6eb7a578028bc3f3f4a476 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 11796b9b864eb000e3fba1b0b6a94984d8324232..de7e4f497222ffc858d2df762c27003c08874722 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 62946c2cb4f8b1d579f42cd18c5e72a6e4531434..693ac3f4de5aaba92d2a2a7f7004be468b1b0b77 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 1cb25f69a96dbff9b4c93b0e3eceab93798c8146..d1afdf684c18c55a5899238dc0843fee40a08cee 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/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 14dab6ff87aa4816a6f84b76ada07a295f52a4dc..b4341110ad4f43eef5038a9e3d82a7b2644b2ab8 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 c7fb878ca4935a338c52c7315eb226e1bc76316c..e4cf980192658fa1d02959ba55e69ec03dc24ea0 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 04c45a10299254586729e1125a255179ec5ef66a..e2b6d2cf5c9d6e48150c3dd52be102ebc85574be 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 2761ddb08501ac3f78a0f8b313a4bebedb1fa775..4dd281f2c33f29b275eaa64cfa80a62d0c62c109 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 da577980d390cbe5df8343f3de64240b4f04c528..4ea5fcccac02d1ee6f933cc1e5b8b8e0260da3a4 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 a3684a30eb69d215f9631da775281c76a23b981a..b30bd430f59120b812dac8feb1732d2edb2f3f22 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 f78bc008cbb71b5695b00b5e6c4edec4509f2175..9cf6bc7a234f8d7bad6df0cd2733fead4cf11301 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 0040451aec1dbd1d1542631072e3e4c0cb71719c..3dd8ed28adc8e92dad4c58c4a4663887a3492f8b 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 3a9f6961db2d6abbc7844a41a7a8cc939b2b9ad0..6a22cf5d35bdde323a94f2aebc20fc3dc4d4264a 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 25c7a3f9652d92781ea03468c369bf0ba746bbf5..ea5d84a1fdad71ad517eba174d5ef1a0fb8cffb0 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 6185af2b33109c5ce8c1ef71a93b35eb2542bfdd..5bca794577687046f4b978c58066f7e7ade7f516 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 fe83beb8f1b7c3f5a0c6b679f209145df77e644f..b68b1e519d53d02d77b8a89e73a1779adda2138c 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 8872642505c0a71a027ccbce25d2e9f3eebe468a..58df98aec1228d794e6b42030192cd6e54012234 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 b8a92459f10f354d763a1e9d3995e28389d8fda6..4da59b4d73f006a4caea2a41c1f6d8b950790f49 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 0f03106f7516ab8a6d1198b1f4b4dd31b06e09cc..2d4535dc2676062a8edf85e4132cea26874f6890 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 faf4e189fe423179cb0261e77a3519a2a2b1c03e..6aaefbad303e0901c2f44d923059bde901168dd2 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 0a77655cda60d6341f379d674b48bce17e6166c3..3045debd5411e26d818309fc3a24c349af0ade4f 100644 (file)
@@ -161,31 +161,6 @@ static void wdrtas_timer_stop(void)
        wdrtas_set_interval(0);
 }
 
-/**
- * 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
  *
@@ -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 9dcb6d0822774a2737c7171600bff911cf799055..d4e47eda41828ea4591a019bde479173e8a4c49a 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 55abfd62654a273c90d27aec2230fecf5941d57a..6489e1fc1afd4222c3e3913c166b1d1bc5cee0f1 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 ab8c1278063450b46050410ff046d41893d54ac3..ff7be98f84f2412359bba865b34314fc62dd6ae9 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 d86edc8d3fd05a0176e73136eedb50641eb091b0..25b018efb8abd8bb82189daf711a9fa4372f3c54 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 c45e016b190f3809366674ae14e109a31a46ab20..3c28cdfb8c477b65269c1a26957cb4942d10344f 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 eec348a3df71877347fc0803124394aa41747dd8..d3e2ea3840bedf2f6e3a2f1b0274172810a17ff8 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 bce87694f7b022b15ca92904d0a6b44875d1ad84..89dec7f789a44335c500e8a2d89fc3f13dac6c5e 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 f8a0b0efda44078c7debba07e2287e91c84405ac..100edcc5e3122323eb8f4087305e623c666eceb0 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 bb43ce081d6ecef40b552d27f2b846a0d1a7606c..c7bda5cd3da74daa998d1fda16c3e78240d7e872 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 3d8bf941d1269ff3afa45baf1ed9f5aee8491431..45e57cc38200448da67b1ce2c896efff555f0e73 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 e66b08882548eb90597fcb6ea0f86139a710b204..1fdc370410576e1a3f5a36a133245468160ae4b4 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 c8ff018fae6887640c277269c649feae49545ce2..f7e584d047e202e0185f4936a71ef189e1a2781a 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 afcb8a1a33b7dcb273eba95331248a781b42e27a..fa68813396b5acb7e7a2e5a65e1202d740688cbb 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 5175aebf6737953983c3da59671657660ec5641f..d62ce0d4814173645f9bbd2da0b0553b527a98b2 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 91d8629e69a24137e48422cb2620361b4e8e47c2..1e57f36ea1b2f84ac43c486cf6aa9cff4b2280a0 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 20efd81266c643338bcd81b434edfe9fbcacc0ac..449b6cf09b09dbc15e90f311e09bc011a0157b44 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 e813f04511d8875dfa81b5a472cea2a932a417cd..6457690731a220b58fa2be3f55bd6bf430f27b8b 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 5da1b55a22581c5dd38daec3164c2ac32eb82a71..04a81a4142c3235f1bb1693b9be4c73580023c2b 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 fff6dfba6204ddd291dd67c4213dfdfed4440c0f..c6ec1633309abad6464995e4aad8352129f5fed6 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 6d15cab95b9908baf0509bceef86fbeb79c93ebd..f259e6cc835791f20e34acce582f83ca1b78102c 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 2b312e4eeaa6c281192c622bc3d54e0327077626..abc9c2809b519c50623209d341733c31a752b2b3 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 f31043b26bd3226ac4ea309d1c29c3ca3f64df2b..36b0d37ea69b8d9f7bab7d1e1e3fcd167afe34e3 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 d4e1eb807457d440f0d75c278fa789dcd4dc5732..1a5ecbed40edac9ae352a1baa2c162697712e9fd 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 09b4fbaadeb6d5c9c79f835f6763b66028e4466d..301b191270b9bcf09edbea5ad47100267f32e859 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 cfa109a4d5a21ac6f784f1a4e8a16b534c9e8d0d..d10757635b9c9360288e18217b28de298fc48407 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 24f1105fda3ab5edfccc7a748f97dd624bf6f0fb..992cf95830b5792a5d510f7d588049d27c139a94 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 e924cf45aad9559533214814cccbb05aa7a06b44..eb1c5979ecaf673d7e984b6b78219217e63c9bc4 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 49ff8ea08f1ca88252d82a34c98d77d0c490ff86..e57380e5f6bd78fb983b10e292919d29eba19abc 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 9a55f53be5ff6a38678a8d52253b14c7e8004941..370d7b6c5942ccedfa8dcd0c92c353badda41080 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 9f4ed13d9f152bff068f68528fc2b1055ee9255c..8743ba9c6742f4c9b2457bd0ef87d58f8bc81051 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 e5fe8506ed16a5305f9c69db5dfbf111ecd085ba..2ae7d59ab10a595120b7a3a124e3e19fe408841d 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 f7e042b63ddb255011c81e02ead0ed944e24c540..f321986e73d28fb2b3aab315087c586dc00870f3 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 9e3aaff11f89cf9d67e2e1289fb1f47003c584c9..d165cde0c68dda885c2f5bb512f48465f521c4a1 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 884fc21ab8ee6182bb0d8ea3f58450b78895a277..04847b8d3070f7bd81708a3c43057119c082c434 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 5fcc02eaa64ca2af23ba4bba6431647fa04deb4e..564c4f279ac630e8458cd74029284c65f44a7796 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 6c50871e62203d3bd9fd81d7c5cde22cfd3f75b4..5ad7748860ce6ceaea7d6f02d689484efcf34cd0 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 8b19027291d6b14b667757256499a750df5312ef..aa8a3370631bd8da9475394ef9f571ed90c620ff 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 8d0c1c7c08204177e5f6f6127daa5caa7c545757..90b3bc21e9b04b6cdf38e7ba288a7ae20ad9266d 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 788e0a9c1fb09cfb6d80ee65e1747310c7c840d0..6669aa2042c30154e0ad318ff5d6d657a2b60f61 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 42d67f9757bf641d316b07e78a3fb1a698f76409..d3472f4cd5301e1c3ac48817755a0c62f8f6975c 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 0fac2cb1ea18648d8befee687f3086f771b8b74a..e474ca2b2bfea832d488536a807ae140073dd591 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 c93639e6cf6827ed9e9b1bd7320bdc297886e933..af6e806044d7cee5d8047a56de6693388fc8d34f 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 a2c7c28049d5096e484bf18453b2be64f17d884f..f1bdb72547768deabc4d0cae87a3271a200e67fc 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 430b6872806fde04de5cb36c32ddc1af49400df9..dc8f1ef665ce6830db7cbf43b327a5fe198fbe37 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 27d74a2945151cfbdf76e41cd381b90a0efe4d09..a7cee864e7b245e5ead7c8f04b509a5cfe9c59a8 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 f17051838b41aeda88075ac9f81f72f3a1559ce9..280acef6f0dc45e29365b197a8242f7d26bb22f7 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 6cd86e0fe450a2b4ed36e447b946970cceaca95b..0c0f3ea90de59f9c9e0c21aebd46e8b07b2f45f9 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 c0d93170585d203e9543b898c5e3691e6234e920..2bbd94e51efc7dcc8bcba377e2e8373290b3a189 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 262df5ccbf59db0c4fd516a30fa721945b55f600..6b9f48ca4c25183abab7759a588a8ec5d4da4257 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 274e2a114e050f02363f90495bcd23c018e646d5..424d8f5f231737780031a903ee575173af8076f0 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 a6bc8a7423dba4c4544bd504bf5b34194a4c8d11..8ff6a0019b0b9cc6016da02c3210ae6840a20dfa 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 5b5894159f22a5261ccd0c5f4a583cdfe0325dec..a4be2e3896704047f1aae87ac924990fb2d0f834 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 3b271d2092b6c7397bc6fa2cb61674290ecc831a..b3ed6446ed8e9a420fedfc2ccbe861c5b46664ed 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 31d3cd12926918978f922edb6e0f01c22d29d864..b800fbcafc7f639f05a83fc97fc5e964f77422b0 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 89042848f9ecfe1726c9322044b21285ab459a30..05c698ccb238f4fa9eef9a1844683fe24f62bd13 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;
@@ -1322,25 +1340,6 @@ xfs_bmap_add_attrfork_extents(
        return error;
 }
 
-/*
- * 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
@@ -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 5f469c3516ebc28bf836e86c974feb8c61373a4c..1cf1292d29b70cdbee6168c9a530d3a891547d7f 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 f7a0e95d197a09ca73401af8b2bc1e8eabb9707b..07d735a80a0f777c342c4323ba9393556afe182b 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 09aea0247d9655c1cd7e9a7c77d1547968222813..5e7fbd72cf5255c53a8494a991986c339ea5293a 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 f01012de06d0b3d3809c4dc2e09c9e5ba6f38982..0adf27ecf3f1cd4e98d8fcc06a732e4d476437db 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 b596626249b84e9eb91d29a2b110e57532d46a60..55abbca2883d84231e7ca61a722f2b394b41376d 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 9560dc1f15a96299392e990da3a08cf7317b89b6..3f90e1ceb8d68c4655bb033da592f495b91e9772 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 9ecfe1e559fc61703228a7c015c989dc95a960cb..b78481f99d9d6a683f0d18815432fce69d8d2838 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 91129794aaecaee513c67d808b704e33a7e60b19..b55fd347ab5b9b9ff51fd555115c854d7cfd8084 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 5e999680094ac87ba68fe21de542525fb2058ee8..6e2bca5d44d67acb52a58115a6b9482fc04a5bc1 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 c69bbc493cb0c7d09cd5d3f8c271e0091228968a..96dda62d497b7e04a68a1a6ddfc579aececf8374 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 bc92c5306a170afd58ca55945bc9471287933699..b93e14b86754a6cf6b12e4e9952e911e10a008ad 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 7a3e007b49f49ceab50aafc84b1a04239a954de8..d320794d03ce233d93f7ccfcd0a6c2c3f186e9c2 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 bdb4f8b95207714cfa97294cd8d2c7a5298841ee..579d6a02a5b6ec5fd2e21c503f4ada8b6dfa54d6 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 2d02eac1c9a8e203886b01c5b67657dae397ce0d..437a52d91f6d91ce9f48acbfc5a9928a9ee366ed 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 a08801ae24e22bf281c6abdeedb1488224d4cbb8..e4f8b2d6f38ba1960beefe35cbd15b0066f530cf 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 c3483bab9cde162f87e069af51f24c19ecbbb005..b14f42c714b609b95eab2b993805a7e4e4e73c24 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 e830fb56e27f9fa0a979dee9f3f58b56e6afa6ae..f4895b662fcb549706881a4dd65a8b048d23d03e 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 3ba64d5401680ae749e36fdd424c6a139db0bdf9..61407a847b869a6bb0faec7bf2c3279d66aaeb83 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 42c0ef288aeb219290ad344bc426430b17a76f52..dc730ac272be8547b304cb6de0fc5de4231c6473 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 ef24466d8f82516a76029577df9c8f1ec530cf20..ec48bac5b039d25cd74829b1ba4c6a1506412dec 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 fd097ecfcd9747849365a0590f91c64f0f7a4479..297462b9f41acb7c95607daa36516b017e37be53 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 282e27028418adc27dcee1f8b7831cd36c4a80ec..a5d52eea82326010feac703f4f7f971801daf6ae 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 4d7390bc172731a88ebbc28d7bd9f76ac3713794..90d5a15120d592eedeff5de22cd33fe61fe98351 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 3cd32478f2fd095817c7fb0b9f6558d336020bde..e151d4c9298d858eca5a3ccd5594da1aebe20596 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 acd0312d46fb13d0a2752ea49add626a1a9411d8..306dd8cd0b6f6136502cab1eefede59319f84ac2 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 99d0fbcbaf79eff04c8ab56531e02aa46e953977..9f15c0064c50586ed08ee740698bcc6f2450c959 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
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 ace9a5f01c64fe1a8ae9d97fe45765ddc375df58..fb425aa16c0149fdf35b9fe6a1be3a56577d3ff7 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 137b4198fc03ba31db01a8112f2feb313abc0420..27d9da3f86ffe91c9d06aa3dc779902adbc620ad 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 3793ed7feeeb1de4f0eec721da5bf008b92f786d..ccd4260834c57da2ea30fc5b20714ef15afe076f 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,48 +113,12 @@ 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 0b176297aaf6337e231785558b99ac93c5b6bac3..7125cef741642b77ca5c41758c26e500be3a2672 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 db50840e6355ece37b36106cb3a9fa6d3939f8d6..6a45fb583ff1451c1b1e67a3cc7a438a92ffba6c 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 3c1c6444ec4b7f87c39ce8645441ba20bcc2cd77..bfbd12b41162bcca18a67be96e070629bbbe841e 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)
 {
 }
 
index e9ee806a9d727ac057a9fd12fd032578e09dfb0a..813dae960ebdcc994af86d80cb02dc8f109090aa 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 f99d57e0ae476dadf6265f758f56a95cded862b3..50d04b92cedaf900532f72d1acef35d04d7ecb69 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 b10ce4b341ea79f8a6e14e63dd458308287b9ac4..230c04bda3e2da37e2c8ce387b3ef0e8c0a36118 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 303399b1ba5954a6de412114b15df8fc0def1514..6ce690de447fe80f5967fbc7b459cce646b4706a 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 161463e596247824f774df256580d08e9dde895f..1f911ccb2a75655bee357d27076b455776d4d377 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 ff374ab3083902a7052a07b2ca8bb40cf3136338..8d71d6577459c9f92d7f21e3ce7c8e76825ab714 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 ca3ad41c2c82ad14615d402712d2b50d1e094272..b300787af8e089b05e4038d71fef277fba9f85e4 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 42628fcfe1bd890eb20ebea9ec2073fa5bdd8137..de59364d7ed2a98263bddc76e92dd5c6414c0574 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 eaade9815bb63fa885ce25b55b5856ee017a1550..12155a9596c49c89350f1cdadbe6f1f301e27d10 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 0c16f518ee092c50d2af5fd96099e9527fa57486..06bacf937d61f2fc1ec4af25afe48e87410c38a2 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 5d5d3a30f04aaca16df5d8bcc3e933721378c5ff..6628f5d01f527dd5d3469a2d2b05ab3899e1ff9f 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 f50969025ef3ca376a418683affed3cd9b14231d..b975c285c8a92ad97731b139c1227713c780bcdf 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 6fdb6adf6b2bd4a3c3c788a7bc1487fa21634a58..7f57056c22ba6d74743ddc1cf00d36e622ead8a9 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 c586c4f7f16bb261378f3850034f6f8186fa4510..14030db51f131ab845277c3c1b879affbb67e9ff 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 ff77d08c30fda6062bdcc45ccdf8327e1560b506..34d2414f2b8c0a6207fb3d4dfe2c34d644f7d6aa 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 980ec51d574d3bb76125d51bdba73054d86cfc23..a7b49297da82ca9792d9d55e1bce8190cc3f9537 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 a8ad75a9152a7e609f0be55d8f804f0e9b72c21f..4a1191abd936df57986be2f99b44cfcd1f0203ee 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 ee4353459ef5c02a0910657d39d27800d51717c7..fadb6afe9ef0a003ef8db8c5db3733321b55c744 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 1d93c48cb3718ee405ad70a1958e1d2e26f2dd69..015ff82da73ce4aa0bf01de390b38be261cdd1b7 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 95d1c91770f4a4d37d6931b607ab4ae94d2a34a0..c768c9f8abc2ca0f1125cf7c1ce9135587bbefbc 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 e6aa2318367baa39bff7c260b828cfab15c4d8ac..0286c95814ffa42d32134f81c703b13a91b84638 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 931652f0e2af9e20a7d79053cbd718e8aeceaddc..e0b74a430b3aa0597b8aa86e6b906206bb34cf25 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 5298d678d0f38c6d8030b23ee5e4f9e55200cf65..3250cc5e79259febddfb7a9472114281a8f4b1f1 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 adcbb20f65118be16489b65f2e087d3bf3128980..d9fa68f26c41c34c33db5f743a4142faf7886792 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);
 };
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 99965395c5f3a5cebb645a67f76681985ce3da84..f3ac0f2c4c66f46cfbd36d16e6588ba121f90832 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 8275e539bace51eabe8a952bb9a680dfb9de893a..125f8714301daea0ef4108683c9c6814e65a5018 100644 (file)
@@ -401,6 +401,12 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
                         struct ib_sa_path_rec *rec,
                         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 98cc4b29fc5b530e087d87e9b509a4c934dadec9..645c3cedce9ca7abb69c13769a05aff02d4b5dd4 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 ad3a3142383af96774227410ae8da9b801abe2aa..1ed2088dc9f5f029532f0b09765cf01a768624ba 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 23a87d0cd72c22ed876463bc997d5190ccb635d0..e5d09d242ba3be8e89df14b9e0611dda759c49be 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 *,
@@ -66,6 +72,10 @@ extern int iscsit_logout_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
  * From iscsi_target_device.c
  */
 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
  */
@@ -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 4ea4f985f39409cf8e03c03972e5b923ca756fff..e34fc904f2e153f8bd6e1c3162fa914ca0bfb189 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 612509592ffd0e2505299066f14e1f9c05e7d1c7..713c5004f4ae8e559349990d72da0d710ae4e44b 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 1dcce9cc99b9bb0321b0ad9419adadb41a1c1346..7a16178424f9af3e9ac57eceb1629eda100fb0b9 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 a26fb7586a09e535b503c48cfa2d158736f1c7bf..b32a14905cfa5d8eab71c0450cc6ef4d0a383c85 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 84bc4197e73659c3ff48967e7710fbf5fb549c36..fed853f3d7aa8a637209bcd72f042a177b754aad 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 bdc6e87ff3eb379cf223a54d6976f36ce96e7fab..997f9f2f09630ec2914d8b59329472fa1dcfc5a4 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 7e75b6fd8d458f06550198a3341e8fc03af9a4aa..afd0cbd52edb62b501bbbe4225338af6b9dc95f0 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 69bd5bb0d5afdf4cb4a484cccd836f48d7f29dd5..e90a88a8708f87e3c046676fca9821d24034a1a1 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 87ee4f4cff250af6aff36e502cb484a2ce8a9bba..916e444e6f74f38745353ec96108dd63e6b91a7e 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 f40b41c7e10891c01234e5e24b42f534db4631f9..95ef4551edc18735d7a4b7b2639bfec8b341753e 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 b7cda390fd00527eac3a2bdfaf93e56581bea344..3ce768c6910d1664376f21fba0608a20ff7523c9 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 1ee9239ff8c2aa8db3cc92cd09d7e948eb2e9fa4..99b80abf360afe3a4d94393df9ed52eb943d42ae 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 1db3af93370410ed8538e04b785f7cb2a3e4b33c..eba8fb5834ae2e7d527693d7eff63556a987bd9a 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 6e6a1c11b3e5939bda764882801a5dd28e904f30..66635c80a813e876d3a3529ed13ce410ab987c4e 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 10e663ab1f4aa0c88bc120660d824e50c099f9a2..452d6f2ba21d9ae0b2b6cd1a966721b325ec9e23 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 2d7cd342836526a1eaa4c767dadd351dee83c71c..706724e9835dc07f72ca1bc21b1cba0bf86f5d65 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 cab4bce49c23dbe3779d02db8259dda28b7b4258..206915830d2993bc54124b0fecf09abadac08a0f 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 e581ada5faf42b7cad697a6a2a9522695f0210b1..ff05f4bd86eb6acf10ff49307e448ddb8b00916a 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 97712319f1284152366e0cd5dda3cbae025bcbc7..8018646005144c4082da694b331a1f44964134d6 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 53b958fcd639eb2d93d9bed73cffbb9250df7c06..440e65d1a544c2d7bea49efbb45c1fbd2fde3a73 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 8212c1aef125f2d4290cbe0e55564d7e9a5a57de..d37d45c90ae6fc863a257f75751976a4bfe2f9ef 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 9b1f2e533b95cf2532ffcadfc62476b18d9e27f5..0d8eb4525e7616953d1a0df16fd43bcf6fc4f0cc 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 4ce13c3cedb97a8bb4eb402d02bc10f79c35245e..ac09d98490aabc0729eb1a4691e8d2b1ec10a34c 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 6d3f91631de62cd94e2c216e96ac56092332e126..218bcb565fed0f6e8f867b9e3e2264812d9797bf 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 0cf1c14531817eacb61eae48f6f76a45a0cc8027..69601726a745ef0ae4cff7c44afba6473cea2c82 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 6c508ff33c6206df8e028e1eab43e913565f927e..67708f46baaefbd6bca64a34a213c2cc7fda5074 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 e71a8be4a6ee9decd1429eb13159885f8c567469..0cd500bffd9b0a26fc9d5f7107f51e8037e1d4bd 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 20572ed88c5c3b791bef107aab7fbc1f3b0b44d1..4a4f6e1828b633aa8a2ba8a7dc6db70ac87db6a3 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 27963e2bf4bfe141d0884bbe9f05b0d74a7fcc47..7d854290bf817ef8c6b116b031830dc060ae5dc7 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)
@@ -393,17 +409,46 @@ static void put_system(struct ftrace_subsystem_dir *dir)
        mutex_unlock(&event_mutex);
 }
 
+/*
+ * 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 e1b653f7e1ca101f0861351d610b5c8297a4b3ca..0d883dc057d68fe92bc36f0510298cff725256bb 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 c4d6d71919888b47b9e6a2b9eb6e25870e247b18..b863f93b30f35caae4239629ea56d05b58b38639 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 b19d065a28cb44b303d74d1a2ec6b13a04ec734f..2aefbee93a6d574a0ea082632788a1d5c7791474 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 9f46e98ba8f22a712962ccc68e17b34f166439ba..7ed6976493c87ec2d31637a60a285bc39b4925b8 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 2901e3b8859066ed32a703143f0372089285109b..a7329b7902f81fff4c2bafa3d4ef29780b52fe3d 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 8f2ac73c7a5fd9a6c8412b7b96e1cc0473651d62..322e16461072575e6d8439208891b5730bd41438 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 32494fb0ee640eef4548ac380cd158eab7415083..d5d0cd368a5635737f749324b61d1037c361c968 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 05039e348f07e242c63392a8758b8371c1a42beb..1241d8c91d5e75efb3ba08ff18109a0a4f84e12c 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 88c8d98767024bf2e9331e16855b2bbc09dc8412..98ac17ed6222a8982bd6a7435e0269f91e4de195 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 aad024dde3c476c9865c1153fd8d57de266d4dd9..6dc09d8f4c248d3765775c7ebf66869c34b4cff4 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 7e28ecfa8aa42663ba3153a984ee1dbe69f7e96b..8028dcc6615c6bbd533adf060ea3d9db36b9a48c 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 72c5acb9345fddc928cafdeb8c0a0bad3279f6b4..f00803386a67e4d7c98ff3d162d61c137cecf0d6 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 f81311173b4d8fb364da906a3efac5b164c07f43..fbad7b091090d12ba0b101815fdc8699b092ee0d 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 e44e6e0a125cb7148913f42fb8ff3e1587a49be9..ecd1f158548e95a51cf004ad3f4d4ff7acb87a88 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 ab1424dbe2e6c9396ee66ab4446f1bc1cd557382..7441c41d00f64df8b2f2439d3bce661cc12c1966 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 01f1779eba805c0e32192280cbd73be6500aab08..8b93cae2d11d7d013d50c276bd08fc11a1187d08 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 02efb25c295705141b3c477a2712864674ae42cc..3ffda1b3799b54340a0ba7851fa0f1c3cea6710c 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 2c69ddd691a16a0056ed071695fb3ebc6293a917..928f2bb9bf8d5d4d43d6324c3ea989a9daf12728 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 defa9d33925c382264b104ff43fc70ec3f1fcc32..27ce2624093217d9f3233e19ccd8062f5c2c960f 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 b05ace4c5f124886f165e2f091713397dbe38df4..d0347d148b34320fb2a12a3ed20c6a2e5222352c 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 80fe5c86efd1265a770a5c9a84f0cad3e78b4940..49eb37010aa35da3bba5e237a7cff107075114e0 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);
 
index f0339ae9bf37efe9bf30acecd3639ae092c27fd0..aa401560777b22ea0ec54abba730007f3347ea57 100644 (file)
@@ -290,7 +290,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 +299,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 +310,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 4679df5a6d50f00efaac83cefbad73c43f0890e8..61239a2cb7861ada7771855aee937a01433441af 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;
@@ -666,11 +683,8 @@ static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
                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);
 }
@@ -1117,6 +1131,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 06bdf5a1082c850030650fc3957f47ef75ebda8a..621ca7b4a1552e393f332fda279be25d7f082152 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 0f679df7d072794094ece1aa48988e834395d849..305374d4fb985ec4942040447f91e8d8277ea10d 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 412de7cfcc80494130b3cd611f698f335e399e4a..ddf0602603bdef4ac0a6ad29a9815bae56f04626 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 182084d728c82d29b69170e642b3e978a8266f6e..8ccf83056a7ab6b260a028a9ee9a422e6949525e 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 6031e2380638f5f492eee301f3f3a8998ec9b0b0..49392ecbef17baf113bb9e3771384d06413bbb25 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 06fcb3333247358c29b15f4b222b2f654d0e1465..bbf901afb606bcbd8c01e09a2b5063f4ae522e76 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 7d4771d449c3491e24ed9ff701a56e6991c108ac..bd5d08b882ee9ccda1d79da6f596e34f0ec12ef1 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 046b9b16f8f9447e7c095f279cae99337ffaa3d8..52c55e4fa67dd64499e7318ccee7371ee023bfd6 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 a9694a8d3e5aba722e03cd130a8d6d032e27a8da..9594c9f7eb8d9c5552ea7141138969230f00d691 100644 (file)
@@ -4,7 +4,7 @@
 //
 // Confidence: Moderate
 // URL: http://coccinelle.lip6.fr/
-// Options: -include_headers
+// Options: --include-headers
 
 virtual context
 virtual org
index 46beb81406ab34661aea4d049e007ae12b124de0..562ec88b6352d4c449361abc484ca9e8601cd406 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 07a74b2c6196c0dc649aaadeee908272ed665d15..09cba54ed0cfdb3f788e6ea1eadcf1e7cd158012 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 4dceab6d54de5deabae0ac3eea2aa6d00da275d8..3d1aa71b757913c31a9375be94a9d13516c658c3 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 2b131a8a13069478ada25059346480e5489c4717..c606231b0e4695683327bdd92132879dd1113bbe 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 15f076fdecbe073474e3eeeaf9e813a3fa77667e..2274638d005b3f5e9dfb4e5636b9c7f0bdf7c4dc 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 05962f7be155b3424cc44437a21e4dc4901b0023..b67e174f3d95effd048f0bf15a412aa536e2820e 100644 (file)
@@ -4,7 +4,7 @@
 ///
 // Confidence: High
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual patch
 virtual report
index 0a1e36146d76dcdfa20eb948d0ef4c4f4f941e70..3d9349012bb3b3bafec7f21b62464e818d6ef4f4 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 d9ae6d89c2f57e9db00a856f461b1f968cf07018..577b78056990bb01e56420b044932a1e187adc40 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 0a40af828c43a4161b94d2b9c85a66830ae60f1b..48c152f224e1395cbdb9a133aa9041ef756c91db 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 259899f6838edaa463d16d445e7f7b8f39d132f6..f58732b56a403a1266baa96b6e7692e9c085861b 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 b2967475679b3926179e466cf6285b5b229969e6..873f444e7137f0fbbde99b683a382fbd93c3d472 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 06284c57a95136b5badbda64c35737de9a2ce84d..f085f5968c5238d631d6239c9d2a92a1b85fcd91 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 8f10b49603c32e11b9c0aa2845da8f11d7901f5e..669b24436248d33a5fde8694375c8528de752f08 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 63b24e682fad112188d0bdfc5b4c80d9009f0a13..002752f97dcab4265173fb5205db3ff393e9bc1d 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 1c4ffe6fd846746d64a1a34168fb3864f18b9af8..debd70e46267f00a06e33a4b59dfeabb945bce4b 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 3267d7410bd5072aaab32efd8d5e4c4f06205618..47f649b0ea876593353ed045657b2632f17beb72 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 97ce41ce813596a98952757c68a2104a0dc7c6ba..b9abed49cd95c5c99841a4e5016eb3c4fda4c1fb 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 d42564484528c10a8382a3f8498a6de012ef6c78..f0368b3d4563ce3a3411d626ec4e76b4ca2fce60 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 cf74a00cf59740d51f828f3140460f77268c1d40..c0c3371d25e0c748533455fee1d4b4a236f50ba5 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 3e4089a770007d196ed872751f0f589bce34e9f0..8aebd1875e75264016ed2ff37a7a21a047b7feae 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 b7ed91dbeb9551d1de29919c253f8b5862d2ac43..d0d00ef1f12ad0503113a1f0448ce75192f44506 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 c1707214e6025cca3bbd82b0673d8f6ac43621f8..80a831c91161a88deb402a5d4b99beb889d60484 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 4a28cef1484e509d7cdd353a2da42cfdad2f6cec..81fabf37939033eae4224f9cf9a99320e6f765cc 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 fda8c3558e4f3d2d28429b685d51569a93858784..d2e5b6cedb84da42db3f7c68bc7e68724a3603c9 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 ed961a1f7d11b28c8e9581e4bffa43edaa495a5b..9bd29aa833995d8a74a9b5fdbcae9dadc64a2dfe 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 949bf656c64c69b78fbe41ac66d55b1587107a03..5354a7903ccbe5f76a4dac24b9fef455bfd1298d 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 9ba73d05a77eec771d706b2656cebab30530167f..72f1572aaec36f737f277eb6a22d6b231dd63f1e 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 13a2c0e8a4bf9cbbb146a00ec23ec44cceb85d5d..78d74c22ca12da130c77702f98741fc4c89e3724 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 e8dd8a6b28a284894ccc4492250112025108031a..cfe0a35cf2dd219090d6186996fd3a5ca6b94fda 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 a65ecbbdd32a90fbadf50aa9622ce555294cf350..567120a87c39c0152643fba45f5487979b305afc 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 643764f53ea7288ac7bb78aea7512306ea171672..5de5660cb7085ac899df9f9dc87989bc931f24be 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 bde5b95c8c19dadea25bcb357ed6362daeb4f42a..d19944f9c3acb9e6004ca13a1f6e4444174a5359 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 43eda40c38383e007a3ab66c755a86a085eef9cc..c55c227af463008396bc32548337769f71cc0d15 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 cdd48600e02a9bd842f2e43ab6b7f263949451ec..df198a5f482217781e7d4a605962bf443881ce7b 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 f8aee5fc6d5e607625fc9e7f93bcbcf7f2e9f13b..09f4edfdc91132887e1e54e09faf1a9b99865965 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 ef1a7381f956d5e7d0ebb8d3ba6af2361a0c3c74..ecdb9659b67d245da75eb60c82d3f4c070d1d68b 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 a2eb80fbc896fe28b2b0f8efc614cf83fcbfc7b8..3b15c08ec1fac369f9b6e0b01c738e46fa3efb2d 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 1099337079b6ab93463ddb9f707e518adcf01666..b4343d384926600329203b846855f940b597b5fd 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 21404a04d7c34dc37d9f29ffe804b6abeb3f2a62..447a582198c9bc70c37c4d2d034b128b5a62080d 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 38cd69c5660e5163bfc402617de0d702e3372bd6..c93de0b2faca28525588bceb023f99bdd8a14acf 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 a48bb93e09073f05ea14786fea9370202f5039f9..1773319b95e74f68ee2c618654e8ee00c96b1b37 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 a0e97c29941023a36ad05708610e62853818255a..58a8289dd650281c29f8e34827c153e9b4d4ac74 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 4e6e8090c20b573868e3cfe15015a6b6f54b2f69..676fb2f824a3d41c81ef5348a4efc3630155cb14 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 a69cbd78fb38e62f3f6c3978ef6a3935551aaabc..6c9c45f9fbbac432a877112f4243f483ed01e9e3 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 fd3f0180e08fbafb537e128c9e46641288c68774..7e233a6ca64ef7faf1bc9390ec89cb90ccef2d98 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 dbf31edd22b261edafc003e6c3e0c3420e866c97..7975d8d258c3f6cb8848a137a3f263a4f16f1d20 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 9f8c44ecc703a1ea9cd27d3e656e5352f8e6ba86..8275f0e55106bc0055d0a1adfe2a169ad1b54193 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 ecc5aa5f865db7d253facefc10cc77fc2404e41d..d550300ec00c34e5b1748478c6381341e9412e0b 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 75d59fcd48b8268bbd4254bc2478ab12ca641b7c..c11212ff35105a66430d27c56b1f00de56c556fd 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 d9e67b719f08e013d4d8da8aaf579332e19f9c23..23708636b05c873f78b1ef5911eb795ba7114497 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 fbbfd08853d3f7c9730cf635177a689b7ab5f380..fdd3fbf4d4a41a0d8bab7b93d5fb6f4c7896f94d 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 84b88f109b80fcc2d7e25e594431bf3a6374962c..d105a44b68f664a55559e38217dcf27ccf025b70 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 d32e16e3c6ae661163359f70f1fcf6c66c49dae3..32b515766df17c984c6a1c56c86fa67dba4ee25d 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 977b0d878dae44de0e1a5c8d0de67df31da3e437..d97f0d61a15b5779bd10a17ef3d90a184673c008 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 14ac9b0e740c2a40e816b36ee7bbdf04601135eb..8bd2261498680676c0b62b7861fbd5be2aa4daac 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 b1dc7d4264385f9f67ca9df57d15f33c88b09add..e2de9ecfd6417146dc9976f85017bd34be9aef4b 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 7a8bc1220b2e52ace3eec9a6e928184c27546cdb..3f726e4f88db8c2900840819e5d86ede5e9415d1 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 49d870034bc34fa7061dd255d9c0f997614c0691..54511c5e6a7ce8a75a2bc5897dd6a7d6085e007d 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 249cd230ad8f13e62aeeb30d18d301ff2e776384..611179c3bca48c4ca0e9128f3ab5016766373e44 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 82ebb1a51479a7afdd4276b135e7c306092bbb3a..7a1734697434487e13b0dfeeeadb614ae24940d2 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 20e98d1dded207ec328e94dc3187b6d025cfc06f..e5e81b11100108dbb724de7eedb0193836351253 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 5b01330b84529bfe9ebcdf43804e892982a830ab..1bc45e71f1fe0217d25ad6b85edd396458cf123d 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 f4912e2668ba0c791a94f4d4c4661100b494e1d6..84c17d836578a0f7b4743af673e56d830384341d 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 c99d45a68bda8a0e7c1054dbf81606d4417eef22..8fe9f2488ec707b67c51763b608410676dbfb3dd 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 0ac34206f7a7c6fb44f92bd664f71487084580e3..97bca4871ea34d8b1f4adc3422907b3cecb5c45c 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 07a03452c227e3804a04661f26e7ca8cc73bec35..68f67cf3d3182f5dcc696a50f3ef889c05ea10d2 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.
@@ -694,6 +702,12 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq,
        desc = vq->vring.desc;
        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 2c5a19733357cd31654fdcf2bc9f0451c1c7be87..280dd820543039140f6c44a00e4518a2de1c6078 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 eb30044a922a3fa2669371c859eadc231083635f..5a37a7c84e69891fc753f205c50b81d22238499f 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 77f952762426661615d3d0180ab2728010e6069f..a4e3921564883a53b317140032a92127b96988a8 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 d4da111ef53d842619d229a5c57c87352bcbbef1..e297b74471b8a32e76912342f50f77534360ec87 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 203cb0eecff2baf1419cdd7339d424cef92df505..641fccddb249964e30de988a056f229e8265283f 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 93c83e3cb4a7a350a439c691103ad008af5c9585..25fd3f1966f193e50ee60d12802d0538f8e18693 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 c6e4bc52349279bcf7d1aef2fcc1430e1f03e74a..4a2f12081964163c3f93bede8934c723806d16f2 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 da8f8eb383a0bea2b7ddefe923836969acbd65fe..0aac5f3e594d87674af00d9a5ef6172d05c16baf 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 46878daca5cc723b3200763e023744e87c7dc2fd..0259502638b47341cbd5c191391864b8f4df7dcf 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 4258300697493ecdd2758c82a080834ed7f69dd6..76543a4a7a306fc3aa60c44f5ce33383e9fba081 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 fff985cf38522cc0cb3a442de32e545529861514..ecca62e27b28f87a8a6c6d6aadf2515b1267f07b 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 ca98d34cd58b533491a255c8349795f581afce17..3662047cc6b1bcd881c8ca833988b2007cc66869 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 2da2a6ca22bf602e8acc8a023bc939b1be53ce6d..fed9ae432c166d2f8d179bfb8a1fd15123112a7f 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 7e910bab1097ee4f9915726c7f36810e15fd7851..352fbd7ff4a1a16eda225109a9fb7e92460f6ed6 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 ab4cf232b8522db25dfaeaf399c05790053d39c9..4536a92b18f3196d9fa532ad193184d3d39b7af8 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 f036af9b6f09f00e52debecafe09a1c930d3ad12..e06c4f8693306827df06134a765d615ce27ae1cc 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 f139dcd2796ef8f590d439234b0cbb255378394b..b5d9238cb181d893d515b941e8726f4ea5abc818 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 8ef3bd30a5492afa002c928b4483e03ac16db790..94d2d4f9c35d0e39ed0b570b033aca5294611736 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 c1e2ed1ed34e4e16e3398acd12f3e5723a81ddee..8c7ea42444d1cb455f03dc1ebcbbf4f33fafd598 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 055fef34b6f6cf791a4b7daa8e73a8e3765591ff..15a77b7c0e36f155c968cbf59780aec089c53f3a 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 6f7d5a9d6b050ddec28b0b76461e155c8829794a..c4374f07603ce14b717f86d087680ab006f99e23 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 450199ab51b5d8364dd0393a75c5f04d913b6300..d51aaf272c683e26e76fbd9f9b57d44c7e467c07 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 99b43dd18c57faf34598ae9b777327b048dab9f0..8065ce8fa9a5cdaea730e55667b7c5ed1d9b77f9 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 63b6f8c8edf28715d0d2e74cddd284e0d4d093a0..c9c7494506a1e7bfddde46ca242f0d583f2500e3 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 738d3b8d97459e12418bdcbcdf7eb8cbbc319b2d..a4dafbee2511546a97b9b9c63cb84fe76e0d19eb 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 6c8bb0fb189bab72966b65269023d0604653db90..995fc25db8c61c401a150b6813869047a7ccc7c3 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 8cf3b5426a9aa9ddab8021bbdda944dec3c5e136..d5528e1cc03a0d72a3676597897bdfd6bb6a811e 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 7a484c97e500cf6dab94a443729d242af5053d7f..2732fad039088ab97369bbe6e727b950ef6a0dcb 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 e60951fcdb123d53df03e5f564cf22cc51ff73db..39159822d58f8a895b8703486339085439ec7c72 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 d875a74a3bdf874def9f54780b00f0ecd5528e56..cbfec92af32766b2570cc9add2ce4c3290bcd75e 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 e01c35d13b6ed0c98c8afb1db3f9b21375aebd9b..914cbb9d9cd007fa8c3c8b9202991e5d51c9c648 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 c10496fbe3c629c270d6b9ab406f587c8b4736c6..2284c8ea4e2a51262e33897087ce5dace9acdeeb 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 8145af5f93a674b861f907d05639b06bb637ffb6..75e66de7e7a7fc9934ec005667c6857cff42ff04 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 52bee591c1c565f3bf9760505c7a824122d2537c..7efc570ffbaaeadf40347880d3f2c0e7a7799f8d 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 38ab91629463f31e2e81bad84f977a5421a03afe..5cdc600e8152efae140687df6a532933e196cf59 100644 (file)
@@ -87,8 +87,35 @@ int sysfs_is_cpu_online(unsigned int cpu)
        return value;
 }
 
+/* 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 8cb797bbceb0b565a5f698e68c71b856dbe2b37c..d28f11fedbdaa0231d2047770fbaffd771c803d1 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 e3f8d9b2b18f027ff2623f16431cc090d004d63a..0d6ba4dbb9c7181a5ed3adc66bda613d3898cf43 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 a99b43b97d6d331d85d2e3610ff9bcdbe04524ff..efc8a69c9abafea4c492b52457d5f645254c3180 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 f03e681f889198604febb510dac7033f27477c56..0d0506d55c71348a3ddce72fcec03824ed987bf3 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 3039a7e972b6cae8b90e57c17d26fff802c3096c..28ce95a059978563eb42ea4942a08e186d063ae6 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 cd801838156f742e07e19a918fb14de21a8f76c7..8447830407037ef065015f1ab360ad0793a642ff 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[],